laravel 集成 workerman/gateway-worker


1. 所需要的包 

1     "workerman/gateway-worker": "^3.0",
2     "workerman/gatewayclient": "^3.0",

 

2.  创建启动文件 这里使用 artisan 

1 php artisan make:command  GatewayWorker

 

3. 编写启动文件 

 1 <?php
 2 
 3 namespace App\Console\Commands;
 4 
 5 use App\Workerman\Events;
 6 use GatewayWorker\BusinessWorker;
 7 use Illuminate\Console\Command;
 8 use Workerman\Worker;
 9 use GatewayWorker\Gateway;
10 use GatewayWorker\Register;
11 
12 class GatewayWorker extends Command
13 {
14     /**
15      * The name and signature of the console command.
16      *
17      * @var string
18      */
19     protected $signature = 'GatewayWorker {action} {--daemon}';
20 
21     /**
22      * The console command description.
23      *
24      * @var string
25      */
26     protected $description = 'Start a GatewayWorker Server.';
27 
28     /**
29      * constructor
30      */
31     public function __construct()
32     {
33         parent::__construct();
34     }
35 
36     /**
37      * Execute the console command.
38      *
39      *
40      */
41     public function handle()
42     {
43         global $argv;
44 
45         if (!in_array($action = $this->argument('action'), ['start', 'stop', 'restart','reload','status'])) {
46             $this->error('Error Arguments');
47             exit;
48         }
49 
50         $argv[0] = 'gateway-worker:server';
51         $argv[1] = $action;
52         $argv[2] = $this->option('daemon') ? '-d' : '';
53 
54         $this->start();
55     }
56 
57     private function start()
58     {
59         $this->startGateWay();
60         $this->startBusinessWorker();
61         $this->startRegister();
62         Worker::runAll();
63     }
64 
65     private function startBusinessWorker()
66     {
67         $worker = new BusinessWorker();
68         $worker->name = 'BusinessWorker';                        #设置BusinessWorker进程的名称
69         $worker->count = 4;                                       #设置BusinessWorker进程的数量
70         $worker->registerAddress = '127.0.0.1:1236';                        #注册服务地址
71         $worker->eventHandler = Events::class;            #设置使用哪个类来处理业务,业务类至少要实现onMessage静态方法,onConnect和onClose静态方法可以不用实现
72     }
73 
74     private function startGateWay()
75     {
76         $gateway = new Gateway("websocket://0.0.0.0:1119");
77         $gateway->name = 'Gateway';                         #设置Gateway进程的名称,方便status命令中查看统计
78         $gateway->count = 4;                                 #进程的数量
79         $gateway->lanIp = '127.0.0.1';                       #内网ip,多服务器分布式部署的时候需要填写真实的内网ip
80         $gateway->startPort = 2000;                              #监听本机端口的起始端口
81         $gateway->pingInterval = 30;
82         $gateway->pingNotResponseLimit = 0;                                 #服务端主动发送心跳
83         $gateway->pingData = '{"mode":"heart"}';
84         $gateway->registerAddress = '127.0.0.1:1236';                  #注册服务地址
85     }
86 
87     private function startRegister()
88     {
89         new Register('text://0.0.0.0:1236');
90     }
91 
92 }
View Code

PS: Register 的端口 以及 Gateway 、BusinessWorker 的 registerAddress 3个端口必须一致,如果是单机部署 IP可以不指定默认为 127.0.0.1  具体的启动参数 和进程、服务设置 参考官方文档

 

4. 编写业务处理类 Events

 Events 类为业务处理的入口文件,当有客户端事件发生时会触发相应的回调  ,可实现5个静态方法 

onWorkerStart:  当businessWorker进程启动时触发。每个进程生命周期内都只会触发一次。
onConnect: 当客户端连接上gateway进程时(TCP三次握手完毕时)触发的回调函数。
onWebSocketConnect: 当客户端连接上gateway完成websocket握手时触发的回调函数.
onMessage: 当客户端发来数据(Gateway进程收到数据)后触发的回调函数
onClose: 客户端与Gateway进程的连接断开时触发。不管是客户端主动断开还是服务端主动断开,都会触发这个回调。一般在这里做一些数据清理工作。
onWorkerStop: 当businessWorker进程退出时触发。每个进程生命周期内都只会触发一次。

这里我再 app/ 目录下 建立 Workerman/Events.php

 1 <?php
 2 
 3 namespace App\Workerman;
 4 
 5 use GatewayWorker\Lib\Gateway;
 6 use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
 7 
 8 class Events
 9 {
10     use AuthorizesRequests;
11 
12     /**
13      *进程启动时触发,每个进程生命周期只会触发一次
14      *这里全局初始化工作,例如设置定时器,初始化redis等连接等
15      *不要在onWorkerStart内执行长时间阻塞或者耗时的操作,这样会导致BusinessWorker无法及时与Gateway建立连接,造成应用异常
16      *无返回值,任何返回值都会被无视
17      * @param $businessWorker
18      */
19     public static function onWorkerStart($businessWorker)
20     {
21         echo "Hello , This Is His App\n";
22     }
23 
24 
25 
26     /**
27      * 当客户端连接上gateway进程时(TCP三次握手完毕时)触发的回调函数。
28      * 无返回值,任何返回值都会被视为无效的
29      * $client_id是服务端自动生成的并且无法自定义。
30      * 可以用过Gateway::bindUid($client_id, $uid)把自己系统的id与client_id绑定
31      * @param $client_id
32      */
33     public static function onConnect($client_id)
34     {
35         Gateway::sendToCurrentClient("Your client_id is $client_id");
36 
37     }
38 
39     /**
40      * 当客户端连接上gateway完成websocket握手时触发的回调函数。
41      * 此回调只有gateway为websocket协议并且gateway没有设置onWebSocketConnect时才有效。
42      * 无返回值,任何返回值都会被视为无效的
43      * $client_id    client_id固定为20个字符的字符串,用来全局标记一个socket连接,每个客户端连接都会被分配一个全局唯一的client_id。
44      * $data   websocket握手时的http头数据,包含get、server等变量
45      * @param $client_id
46      * @param $data
47      */
48     public static function onWebSocketConnect($client_id, $data)
49     {
50 
51         Gateway::sendToAll('欢迎' . $client_id);
52 //        var_export($data);
53 //        if(!isset($data['Authorization']) && !empty($data['Authorization']))
54 //        {
55 //            Gateway::sendToClient($client_id,'not Authorization');
56 ////            Gateway::closeClient($client_id);
57 //        }
58 
59     }
60 
61     /**
62      * 当客户端发来数据(Gateway进程收到数据)后触发的回调函数
63      * 无返回值,任何返回值都会被视为无效的
64      * @param $client_id
65      * @param $message
66      * @throws \Exception
67      */
68     public static function onMessage($client_id, $message)
69     {
70         Gateway::sendToAll($message);
71         // 群聊,转发请求给其它所有的客户端
72     }
73 
74     /**
75      * 客户端与Gateway进程的连接断开时触发。不管是客户端主动断开还是服务端主动断开,都会触发这个回调。一般在这里做一些数据清理工作。
76      * @param $client_id
77      * @throws \Exception
78      */
79     public static function onClose($client_id)
80     {
81         // 广播 xxx logout
82         GateWay::sendToAll("client[$client_id] logout\n");
83     }
84 }
View Code

 5. 在你的业务代码里使用 GatewayClient 

  

 1 <?php
 2 
 3 
 4 namespace App\Http\Controllers\Api;
 5 
 6 use App\Http\Controllers\Controller;
 7 use GatewayClient\Gateway;
 8 
 9 class IndexController extends Controller
10 {
11     public function __construct()
12     {
13         //这里填写Register服务的ip和Register端口,注意端口不是gateway端口 也可以用外网IP
14         Gateway::$registerAddress = '127.0.0.1:1236';
15     }
16 
17     public function sendMessage()
18     {
19         Gateway::sendToAll('当前在线人数: ' . Gateway::getAllClientCount());
20         Gateway::sendToClient('xxx', 'message');
21         //TODO  更多方法
22     }
23 }

 

  到这里代码上的就处理的差不多了,接下来看部署

 

常见问题说明

  • pcntl 配置问题
    日志信息
 
Fatal error: Uncaught Error: Call to undefined function pcntl_signal() 

因为默认这个没有启用,解决方法:

docker-php-ext-install pcntl
    • 其他依赖问题
      安装event 需要sockets,安装sockets 需要openssl

 

  我本地使用的是laradock  服务器使用的 dnmp

  本地  ---   

需要在 docker-composer.yml  php容器 (随意)部分 添加端口映射 将你需要用到的都添加进去 例如

1       ports:
2         - "${WORKSPACE_SSH_PORT}:22"
3         - "1119:1119"
4         - "2000:2000"
5         - "12360:12360"
6         - "1236:1236"
7         - "2001:2001"
8         - "2002:2002"
9         - "2003:2003"

然后重启对应的容器  docker-composer restart laradock_php_1 

 

 

 

服务器  ---  dnmp 目录下的  .env 

修改 .env ⽂件,在 PHP 扩展中新增 redis , pcntl

修改 docker-compose.yml ⽂件,在 php 模块新增端⼝ 1119 提供 Websocket 服务

docker-composer restart php

 nginx  设置  对应的conf 配置文件中 server块外添加

upstream ws { server php:1119; keepalive 64; }

将ws 链接转发到 php:1119 

 

docker exec nginx nginx -t 

docker exec nginx nginx -s reload 

 

 

到这里就差不多啦 

 

docker exec -it php bash  cd /youApp/  php artisan GatewayWorker start   以debug 运行(或者 --daemon 守护进程方式运行)

 

云服务器需要打开防火墙以及对应的安全组,或者策略 开放所需端口 

 

测试:

 1 <!DOCTYPE HTML>
 2 <html>
 3    <head>
 4    <meta charset="utf-8">
 5    <title>ws 测试</title>
 6     
 7       <script type="text/javascript">
 8          // 假设服务端ip为127.0.0.1
 9          ws = new WebSocket("ws://x.x.x.x:1119");
10          ws.onopen = function() {
11             alert("连接成功");
12             ws.send('tom');
13             alert("给服务端发送一个字符串:tom");
14          };
15          ws.onmessage = function(e) {
16             alert("收到服务端的消息:" + e.data);
17          };
18       </script>
19         
20    </head>
21    <body>
22 
23    </body>
24 </html>

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM