GatewayWorker
基於Workerman
開發的一個項目框架,用於快速開發TCP
長鏈接應用,例如app推送服務端、即時IM服務端、遊戲服務端、物聯網、智能家居等等
GatewayWorker
使用經典的Gateway
和Worker
進程模型。Gateway
進程負責維持客戶端鏈接,並轉發客戶端的數據給BusinessWorker
進程處理,BusinessWorker
進程負責處理實際的業務邏輯(默認調用Events.php
處理業務),並將結果推送給對應的客戶端。Gateway
服務和BusinessWorker
服務能夠分開部署在不一樣的服務器上,實現分佈式集羣。php
GatewayWorker
提供很是方便的API,能夠全局廣播數據、能夠向某個羣體廣播數據、也能夠向某個特定客戶端推送數據。配合Workerman
的定時器,也能夠定時推送數據。html
GatewayWorker
安裝在LInux
服務器上:nginx
下載地址:GatewayWorkerlaravel
一、下載 demogit
二、命令行運行 unzip GatewayWorker.zip
解壓縮GatewayWorker.zip
github
三、命令行運行 cd GatewayWorker
進入GatewayWorker
目錄web
四、命令行運行 php start.php start
啓動 GatewayWorker
redis
五、新開幾個命令行窗口運行 telnet 127.0.0.1 8282
,輸入任意字符便可聊天(非本機測試請將127.0.0.1
替換成實際ip)。chrome
注意:若是telnet
超時請檢查服務器防火牆(iptables
)
這裏啓動的是GatewayWorker
的默認端口,要是須要更改要改如下三個文件:GatewayWorker/Applications/YourApp/start_register.php
apache
// register 必須是text協議;這個端口要保持一致,根據項目自定義 $register = new Register('text://0.0.0.0:1238');
GatewayWorker/Applications/YourApp/start_businessworker.php
// bussinessWorker 進程 $worker = new BusinessWorker(); // worker名稱,根據不一樣的項目自定義 $worker->name = 'YourAppBusinessWorker'; // bussinessWorker進程數量 $worker->count = 4; // 服務註冊地址; 注意這個端口要保持一致,不一樣的項目能夠自定義 $worker->registerAddress = '127.0.0.1:1238';
GatewayWorker/Applications/YourApp/start_gateway.php
// gateway 進程,這裏使用Text協議,能夠用telnet測試 $gateway = new Gateway("tcp://0.0.0.0:8282"); // gateway名稱,status方便查看 $gateway->name = 'YourAppGateway'; // gateway進程數 $gateway->count = 4; // 本機ip,分佈式部署時使用內網ip $gateway->lanIp = '127.0.0.1'; // 內部通信起始端口,假如$gateway->count=4,起始端口爲4000 // 則通常會使用4000 4001 4002 4003 4個端口做爲內部通信端口 ,不一樣項目開啓不一樣端口 $gateway->startPort = 2900; // 服務註冊地址;端口保持一致,項目自定義 $gateway->registerAddress = '127.0.0.1:1238'; // 服務端向客戶端發送心跳數據的時間間隔 單位:秒。若是設置爲0表明不發送心跳檢測 //$gateway->pingInterval = 10; //客戶端連續$pingNotResponseLimit次$pingInterval時間內不迴應心跳則斷開連接。 //若是設置爲0表明客戶端不用發送迴應數據,即經過TCP層面檢測鏈接的連通性(極端狀況至少10分鐘才能檢測到) //$gateway->pingNotResponseLimit = 2; // 要發送的心跳請求數據,心跳數據是任意的,只要客戶端能識別便可 //$gateway->pingData = '{"type":"ping"}';
注意:須要客戶端與服務端保持鏈接不被斷開,能夠開啓心跳檢查定時發送心跳數據。
服務管理
在GatewayWorker
根目錄下有一個start.php
文件:
php start.php start 啓動服務 (php start.php start -d 以daemon啓動) php start.php stop 中止服務 php start.php restart 從新啓動 (-d 以daemon啓動) php start.php reload 平滑重啓 php start.php status 服務狀態
vagrant@homestead:~/code/GatewayWorker$ php start.php status Workerman[start.php] status ----------------------------------------------GLOBAL STATUS---------------------------------------------------- Workerman version:3.5.10 PHP version:7.2.3-1+ubuntu16.04.1+deb.sury.org+1 start time:2018-06-08 14:00:54 run 0 days 2 hours load average: 0, 0, 0 event-loop:\Workerman\Events\Select 3 workers 9 processes worker_name exit_status exit_count YourAppBusinessWorker 0 0 YourAppGateway 0 0 Register 0 0 ----------------------------------------------PROCESS STATUS--------------------------------------------------- pid memory listening worker_name connections send_fail timers total_request qps status 4693 2M none YourAppBusinessWorker 5 0 0 3 0 [idle] 4694 2M none YourAppBusinessWorker 5 0 0 3 0 [idle] 4695 2M none YourAppBusinessWorker 5 0 0 156 0 [idle] 4696 2M none YourAppBusinessWorker 5 0 0 3 0 [idle] 4697 2M tcp://0.0.0.0:8282 YourAppGateway 8 0 0 226 0 [idle] 4698 2M tcp://0.0.0.0:8282 YourAppGateway 8 0 0 226 0 [idle] 4699 2M tcp://0.0.0.0:8282 YourAppGateway 8 0 0 226 0 [idle] 4700 2M tcp://0.0.0.0:8282 YourAppGateway 8 0 0 378 0 [idle] 4701 2M text://0.0.0.0:1238 Register 8 0 0 51 0 [idle] ----------------------------------------------PROCESS STATUS--------------------------------------------------- Summary 18M - - 60 0 0 1272 0 [Summary]
注意:修改代碼要重啓服務。
GatewayClient
安裝下項目中
原則:
現有mvc
框架項目與GatewayWorker
獨立部署互不干擾全部的業務邏輯都由網站頁面
post/get
到mvc
框架中完成
GatewayWorker
不接受客戶端發來的數據,即GatewayWorker
不處理任何業務邏輯,GatewayWorker
僅僅當作一個單向的推送通道僅當
mvc
框架須要向瀏覽器主動推送數據時纔在mvc框架中調用Gateway
的API(GatewayClient)
完成推送
固然,這只是官方推薦的結合方式,也不是絕對的。開發者能夠自由變化選擇結合方式以適應本身的業務需求。 固然也能夠採用客戶端與GatewayWorker
直接雙向通信的方式完成業務通信。更多參考官方手冊。
下載地址:GatewayClient。項目中執行如下命令便可:
composer require workerman/gatewayclient
在laravel
中結合redis
消息隊列(可參考laravel/lumen 使用 redis隊列)來完成消息推送。
在controller
中使用dispatch
觸發隊列
dispatch(new YourJob($data));
在Jobs
中示例:
<?php namespace App\Jobs; use GatewayClient\Gateway; class YourJob extends Job { /** * Create a new job instance. * * @return void */ protected $id; public function __construct($id) { $this->id = $id; } public function handle() { //業務邏輯 Gateway::sendToAll(json_encode(['id' => xxx, 'name' => xxx])); } }
每次改動代碼重啓隊列。
supervisorctl reload
服務器端打開Telnet
,不可執行Telnet命令須要安裝。
如:
vagrant@homestead:~/code/GatewayWorker$ telnet 127.0.0.1 8282 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. Hello 7f0000010b5600000001 7f0000010b5600000001 login hello 7f0000010b5600000001 said hello {"id":"35","name":"xxx"}
正常狀況,會輸出你想發送的消息。Escape character is '^]'.
是 Ctrl + ]
調出Telnet
,輸入quit
能夠退出。
Workerman如何建立一個wss服務,使得客戶端能夠用過wss協來鏈接通信,好比在微信小程序中鏈接服務端。
wss協議實際是websocket
+SSL
,就是在websocket協議
上加入SSL
層,相似https(http+SSL)
。 因此只須要在websocket
協議的基礎上開啓SSL
便可支持wss
協議。
準備工做:
一、Workerman
版本不小於3.3.7
二、PHP
安裝了openssl
擴展
三、已經申請了證書(pem/crt
文件及key
文件)放在磁盤任意目錄
start_gateway.php
中設置如下代碼
<?php require_once __DIR__ . '/Workerman/Autoloader.php'; use Workerman\Worker; // 證書最好是申請的證書 $context = array( // 更多ssl選項請參考手冊 http://php.net/manual/zh/context.ssl.php 'ssl' => array( // 請使用絕對路徑 'local_cert' => '磁盤路徑/server.pem', // 也能夠是crt文件 'local_pk' => '磁盤路徑/server.key', 'verify_peer' => false, // 'allow_self_signed' => true, //若是是自簽名證書須要開啓此選項 ) ); // 這裏設置的是websocket協議(端口任意,可是須要保證沒被其它程序佔用) $worker = new Worker('websocket://0.0.0.0:443', $context); $worker->name = xxx //配置名稱便於監控 // 設置transport開啓ssl,websocket+ssl即wss $worker->transport = 'ssl'; $worker->onMessage = function($con, $msg) { $con->send('ok'); }; Worker::runAll();
經過以上的代碼,Workerman
就監聽了wss
協議,客戶端就能夠經過wss
協議來鏈接workerman
實現安全即時通信了。
測試
打開chrome
瀏覽器,按F12
打開調試控制檯,在Console
一欄輸入(或者把下面代碼放入到html頁面用js運行)
// 證書是會檢查域名的,請使用域名鏈接
ws = new WebSocket("wss://域名"); ws.onopen = function() { alert("鏈接成功"); ws.send('tom'); alert("給服務端發送一個字符串:tom"); }; ws.onmessage = function(e) { alert("收到服務端的消息:" + e.data); };
注意:一、若是沒法啓動,則通常是
443
端口被佔用,請改爲其它端口,注意改爲其它端口後客戶端鏈接時須要帶上端口號,客戶端鏈接時地址相似wss://domain.com:xxx
,xxx爲端口號。若是必須使用443
端口請使用方法二代理的方式實現wss
。二、wss端口只能經過wss協議訪問,
ws
沒法訪問wss
端口。三、證書通常是與域名綁定的,因此測試的時候客戶端請使用域名鏈接,不要使用ip去連。
四、若是出現沒法訪問的狀況,請檢查服務器防火牆。
五、此方法要求
PHP版本>=5.6
,由於微信小程序要求tls1.2
,而PHP5.6如下版本不支持tls1.2。六、微信小程序要求鏈接
wss
時不帶端口號,也就是wss端口只能是443
。可是443端口通常被nginx/apache
佔用,此時能夠考慮方法二。
利用nginx/apache
做爲wss
代理轉發給workerman
(注意此方法workerman部分千萬不要設置ssl,不然將沒法鏈接
)。
通信原理及流程是:一、客戶端發起
wss
鏈接連到nginx/apache
二、
nginx/apache
將wss協議
的數據轉換成ws協議
數據並轉發到Workerman
的websocket
協議端口三、
Workerman
收到數據後作業務邏輯處理四、
Workerman
給客戶端發送消息時,則是相反的過程,數據通過nginx/apache
轉換成wss協議
而後發給客戶端
nginx配置參考
前提條件及準備工做:一、假設
Workerman
監聽的是8282
端口(websocket協議
,不要用tcp
)
二、已經申請了證書(pem/crt
文件及key
文件)放在了/etc/nginx/conf.d/ssl
下
三、打算利用nginx
開啓443
端口對外提供wss
代理服務(端口能夠根據須要修改)
四、nginx
通常做爲網站服務器運行着其它服務,爲了避免影響原來的站點使用,這裏使用地址 域名/wss
做爲wss
的代理入口。也就是客戶端鏈接地址爲wss://域名/wss
nginx配置相似以下:
server { listen 443; ssl on; ssl_certificate /etc/ssl/server.pem; ssl_certificate_key /etc/ssl/server.key; ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; ssl_protocols SSLv3 SSLv2 TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; location /wss { proxy_pass http://127.0.0.1:8282; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header X-Real-IP $remote_addr; } # location / {} 站點的其它配置... }
測試
// 證書是會檢查域名的,請使用域名鏈接
ws = new WebSocket("wss://域名/wss"); ws.onopen = function() { alert("鏈接成功"); ws.send('tom'); alert("給服務端發送一個字符串:tom"); }; ws.onmessage = function(e) { alert("收到服務端的消息:" + e.data); };
另外爲了方便測試,你們也可使用在線測試工具,如 websocket在線測試