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