一、簡述
GatewayWorker
基於Workerman
開發的一個項目框架,用於快速開發TCP
長連接應用,例如app推送服務端、即時IM服務端、遊戲服務端、物聯網、智能家居等等
GatewayWorker
使用經典的Gateway
和Worker
進程模型。Gateway
進程負責維持客戶端連接,並轉發客戶端的數據給BusinessWorker
進程處理,BusinessWorker
進程負責處理實際的業務邏輯(默認調用Events.php
處理業務),並將結果推送給對應的客戶端。Gateway
服務和BusinessWorker
服務可以分開部署在不同的服務器上,實現分佈式集羣。
GatewayWorker
提供非常方便的API,可以全局廣播數據、可以向某個羣體廣播數據、也可以向某個特定客戶端推送數據。配合Workerman
的定時器,也可以定時推送數據。
二、安裝
GatewayWorker
安裝在LInux
服務器上:
下載地址:GatewayWorker
1、下載 demo
2、命令行運行 unzip GatewayWorker.zip
解壓縮GatewayWorker.zip
3、命令行運行 cd GatewayWorker
進入GatewayWorker
目錄
4、命令行運行 php start.php start
啓動 GatewayWorker
5、新開幾個命令行窗口運行 telnet 127.0.0.1 8282
,輸入任意字符即可聊天(非本機測試請將127.0.0.1
替換成實際ip)。
注意:如果telnet
超時請檢查服務器防火牆(iptables
)
這裏啓動的是GatewayWorker
的默認端口,要是需要更改要改以下三個文件:GatewayWorker/Applications/YourApp/start_register.php
// 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
可以退出。
五、配置wss
Workerman如何創建一個wss服務,使得客戶端可以用過wss協來連接通訊,比如在微信小程序中連接服務端。
wss協議實際是websocket
+SSL
,就是在websocket協議
上加入SSL
層,類似https(http+SSL)
。 所以只需要在websocket
協議的基礎上開啓SSL
即可支持wss
協議。
- 配置方式一:直接用Workerman開啓SSL:
準備工作:
1、Workerman
版本不小於3.3.7
2、PHP
安裝了openssl
擴展
3、已經申請了證書(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);
};
注意:1、如果無法啓動,則一般是
443
端口被佔用,請改成其它端口,注意改成其它端口後客戶端連接時需要帶上端口號,客戶端連接時地址類似wss://domain.com:xxx
,xxx爲端口號。如果必須使用443
端口請使用方法二代理的方式實現wss
。2、wss端口只能通過wss協議訪問,
ws
無法訪問wss
端口。3、證書一般是與域名綁定的,所以測試的時候客戶端請使用域名連接,不要使用ip去連。
4、如果出現無法訪問的情況,請檢查服務器防火牆。
5、此方法要求
PHP版本>=5.6
,因爲微信小程序要求tls1.2
,而PHP5.6以下版本不支持tls1.2。6、微信小程序要求連接
wss
時不帶端口號,也就是wss端口只能是443
。但是443端口一般被nginx/apache
佔用,此時可以考慮方法二。
- 配置方式二:利用nginx/apache代理wss
利用nginx/apache
作爲wss
代理轉發給workerman
(注意此方法workerman部分千萬不要設置ssl,否則將無法連接
)。
通訊原理及流程是:1、客戶端發起
wss
連接連到nginx/apache
2、
nginx/apache
將wss協議
的數據轉換成ws協議
數據並轉發到Workerman
的websocket
協議端口3、
Workerman
收到數據後做業務邏輯處理4、
Workerman
給客戶端發送消息時,則是相反的過程,數據經過nginx/apache
轉換成wss協議
然後發給客戶端
nginx配置參考
前提條件及準備工作:1、假設
Workerman
監聽的是8282
端口(websocket協議
,不要用tcp
)
2、已經申請了證書(pem/crt
文件及key
文件)放在了/etc/nginx/conf.d/ssl
下
3、打算利用nginx
開啓443
端口對外提供wss
代理服務(端口可以根據需要修改)
4、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);
};
轉載:https://segmentfault.com/a/1190000015230002