ThinkPHP6和Workerman结合实例


1. 使用composer安装
 
composer require topthink/think-worker
 
引入依赖后,会在config目录下生成三个文件 gateway_worker.php worker.php worker_server.php
 
 

2.配置

本文使用的 gateway_worker.php 配置文件
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker:gateway 指令有效
// +----------------------------------------------------------------------
return [
    // 扩展自身需要的配置
    'protocol'              => 'websocket', // 协议 支持 tcp udp unix http websocket text
    'host'                  => env('gateway.host','127.0.0.1'), // 监听地址
    'port'                  => env('gateway.port',2348), // 监听端口
    'socket'                => '', // 完整监听地址
    'context'               => [], // socket 上下文选项

    'register_deploy'       => true, // 是否需要部署register
    'businessWorker_deploy' => true, // 是否需要部署businessWorker
    'gateway_deploy'        => true, // 是否需要部署gateway

    // Register配置
    'registerAddress'       => env('gateway.register_address','127.0.0.1:1238'),

    // Gateway配置
    'name'                  => 'ZsrdCrmGateway',
    'count'                 => 1,
    'lanIp'                 => env('gateway.lan_ip','127.0.0.1'),
    'startPort'             => 2000,
    'daemonize'             => false,
    'pingInterval'          => 10,
    'pingNotResponseLimit'  => 0,
    'pingData'              => '{"type":"ping"}',

    // BusinsessWorker配置
    'businessWorker'        => [
        'name'         => 'BusinessWorker',
        'count'        => 1,
        'eventHandler' => '\common\workerman\GatewayEvents',
    ],

];
 
 
新建 GatewayEvents.php 并继承 Events.php
 
<?php

/*
 *  +----------------------------------------------------------------------
 *  | wangqy
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023 http://upwqy.com All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Author: wangqy <529857614@qq.com>
 *  +----------------------------------------------------------------------
 */

namespace common\workerman;

use common\utils\Json;
use GatewayWorker\Lib\Gateway;
use think\worker\Events;
use Workerman\Worker;

class GatewayEvents extends Events
{
    /**
     * onConnect 事件回调
     * 当客户端连接上gateway进程时(TCP三次握手完毕时)触发.
     *
     * @param int $client_id
     */
    public static function onConnect($client_id)
    {
        $response = [
            'type' => 'connect',
            'client_id' => $client_id,
        ];
        Gateway::sendToCurrentClient(json_encode($response));
    }

    /**
     * onWebSocketConnect 事件回调
     * 当客户端连接上gateway完成websocket握手时触发.
     *
     * @param int   $client_id 断开连接的客户端client_id
     * @param mixed $data
     */
    public static function onWebSocketConnect($client_id, $data)
    {
        $response = [
            'type' => 'web_socket_connect',
            'client_id' => $client_id,
            'data' => $data,
        ];
        Gateway::sendToCurrentClient(json_encode($response));
    }

    /**
     * onMessage 事件回调
     * 当客户端发来数据(Gateway进程收到数据)后触发.
     *
     * @param int   $client_id
     * @param mixed $data
     */
    public static function onMessage($client_id, $data)
    {
        $response = [
            'type' => 'message',
            'client_id' => $client_id,
            'data' => Json::decode($data),
        ];

        Gateway::sendToCurrentClient(json_encode($response));
    }

    /**
     * onClose 事件回调 当用户断开连接时触发的方法.
     *
     * @param int $client_id 断开连接的客户端client_id
     */
    public static function onClose($client_id)
    {
        $data = [
            'type' => 'close',
            'client_id' => $client_id,
        ];
        GateWay::sendToClient($client_id, json_encode($data));
    }

    /**
     * onWorkerStop 事件回调
     * 当businessWorker进程退出时触发。每个进程生命周期内都只会触发一次。
     */
    public static function onWorkerStop(Worker $businessWorker)
    {
        echo "WorkerStop\n";
    }
}
 
然后 配置文件 gateway_worker.php 中更换处理器
 
'businessWorker'        => [
    'name'         => 'BusinessWorker',
    'count'        => 1,
    'eventHandler' => '\common\workerman\GatewayEvents',
],

 

启动服务

php think worker:gateway

 

测试

import { bindClient } from '@/api/user'

class Socket {
  constructor() {
    this.url = 'ws://127.0.0.1:2348'
    this.webSocket = new WebSocket(this.url)

    this.init()
  }
  init() {
    // 监听是否连接成功
    this.webSocket.onopen = () => {
      // 连接成功则发送一个数据
      this.send({ msg: '连接成功' })
    }

    // 接听服务器发回的信息并处理展示
    this.webSocket.onmessage = (e) => {
      const data = JSON.parse(e.data)
      const type = data.type || ''

      this.data = data

      console.log(data)

      switch (type) {
        case 'connect':
          this.bindUid()
          break
      }
    }

    // 监听连接关闭事件
    this.webSocket.onclose = () => {
      // 监听整个过程中websocket的状态
      console.log('连接已关闭')
    }

    // 监听并处理error事件
    this.webSocket.onerror = function(error) {
      console.log(error)
    }
  }
  bindUid() {
    bindClient({ client_id: this.data.client_id }).then(res => {
      console.log('bind_client success')
    })
  }
  send(obj) {
    this.webSocket.send(JSON.stringify(obj))
  }
}
export default Socket

 

然后在需要使用的地方 new Socket() 即可。

 

到这里表示能够正常连接websocket 实现 前端和websocket的通讯了,
 
但是实际使用中,还需要在项目中主动给用户发送消息,所以这里就需要使用 Lib\Gateway类提供的接口
 
 
如果在配置中自定义了$registerAddress,在mvc框架中使用gateway相关功能时 需要配置 $registerAddress 地址
 
所以这里新建了单独的push文件
 
<?php

/*
 *  +----------------------------------------------------------------------
 *  | wangqy
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023 http://upwqy.com All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Author: wangqy <529857614@qq.com>
 *  +----------------------------------------------------------------------
 */

namespace common\workerman;

use common\utils\Json;
use GatewayWorker\Lib\Gateway;

class GatewayPush
{
    public function __construct()
    {
        Gateway::$registerAddress = '127.0.0.1:1238';
    }

    public static function bindUid($clientId, $uid)
    {
        Gateway::bindUid($clientId, $uid);
    }

    public static function sendToClient($clientId, $type = 'message',array $data = [])
    {
        $response = [
            'type' => $type,
            'client_id' => $clientId,
            'data' => $data,
        ];

        return Gateway::sendToClient($clientId, Json::encode($response));
    }
}
 
使用过程中要注意几个配置项
 
 
1、lanIp是Gateway所在服务器的内网IP,默认填写127.0.0.1即可。多服务器分布式部署的时候需要填写真实的内网ip,不能填写127.0.0.1。注意:lanIp只能填写真实ip,不能填写域名或者其它字符串,无论如何都不能写0.0.0.0 .

如果你的LanIp地址错误,会提示 stream_socket_client(): unable to connect to tcp://127.0.0.1:2000
 
2、registerAddress,注册服务地址,格式类似于 '127.0.0.1:1236'。如果是部署了多个register服务则格式是数组,类似['192.168.0.1:1236','192.168.0.2:1236']
 

 

创建wss服务

 

利用nginx代理SSL(推荐)

 

前提条件及准备工作:

1、已经安装nginx,版本不低于1.3

2、假设Workerman监听的是8282端口(websocket协议)

3、已经申请了证书(pem/crt文件及key文件)假设放在了/etc/nginx/conf.d/ssl下

4、打算利用nginx开启443端口对外提供wss代理服务(端口可以根据需要修改)

5、nginx一般作为网站服务器运行着其它服务,为了不影响原来的站点使用,这里使用地址 域名/wss 作为wss的代理入口。也就是客户端连接地址为 wss://域名/wss

 

上面是官网给出的流程,我这里根据实际情况调整为如下几步。也可以去Workerman官网去查看关于WSS相关的文章

 

第一步:在网站设置中开启SSL,证书可以自创建或者使用阿里云的免费证书

 

 

第二步:在配置中加入如下代码

 

  location /wss
  {
    proxy_pass http://127.0.0.1:2348;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header X-Real-IP $remote_addr;
  }

 

第三步:将ws连接更改为 wss://域名/wss

 

 

通过上面三步配置后,执行命令:php think worker:gateway

 

刷新后台网站,可以看到连接成功。

 

 

另外目前所使用的服务器是单服务器,所以服务器上的配置和本地测试的时候是一样的

 

.env 配置如下:

[GATEWAY]
HOST = 127.0.0.1
PORT = 2348
LAN_IP = 127.0.0.1
REGISTER_ADDRESS = 127.0.0.1:1238

 

 

 

 

发布时间 : 2023-03-01,阅读量:2864 , 分类: ThinkPHP WorkerMan Gateway
本文链接:https://upwqy.com/details/34.html
PHP 数组 函数注入