Laravel 結合 GatewayWorker 推送消息

1、簡述

GatewayWorker基於 Workerman開發的一個項目框架,用於快速開發 TCP長鏈接應用,例如app推送服務端、即時IM服務端、遊戲服務端、物聯網、智能家居等等

GatewayWorker使用經典的GatewayWorker進程模型。Gateway進程負責維持客戶端鏈接,並轉發客戶端的數據給BusinessWorker進程處理,BusinessWorker進程負責處理實際的業務邏輯(默認調用Events.php處理業務),並將結果推送給對應的客戶端。Gateway服務和BusinessWorker服務能夠分開部署在不一樣的服務器上,實現分佈式集羣。php

GatewayWorker提供很是方便的API,能夠全局廣播數據、能夠向某個羣體廣播數據、也能夠向某個特定客戶端推送數據。配合Workerman的定時器,也能夠定時推送數據。html

2、安裝

GatewayWorker 安裝在LInux服務器上:nginx

下載地址:GatewayWorkerlaravel

一、下載 demogit

二、命令行運行 unzip GatewayWorker.zip 解壓縮GatewayWorker.zipgithub

三、命令行運行 cd GatewayWorker 進入GatewayWorker目錄web

四、命令行運行 php start.php start 啓動 GatewayWorkerredis

五、新開幾個命令行窗口運行 telnet 127.0.0.1 8282,輸入任意字符便可聊天(非本機測試請將127.0.0.1替換成實際ip)。chrome

注意:若是 telnet超時請檢查服務器防火牆( iptables)

這裏啓動的是GatewayWorker的默認端口,要是須要更改要改如下三個文件:
GatewayWorker/Applications/YourApp/start_register.phpapache

// 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/getmvc框架中完成

GatewayWorker不接受客戶端發來的數據,即GatewayWorker不處理任何業務邏輯,GatewayWorker僅僅當作一個單向的推送通道

僅當mvc框架須要向瀏覽器主動推送數據時纔在mvc框架中調用GatewayAPI(GatewayClient)完成推送

固然,這只是官方推薦的結合方式,也不是絕對的。開發者能夠自由變化選擇結合方式以適應本身的業務需求。 固然也能夠採用客戶端與GatewayWorker直接雙向通信的方式完成業務通信。更多參考官方手冊

下載地址:GatewayClient。項目中執行如下命令便可:

composer require workerman/gatewayclient

3、應用

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

4、調試

服務器端打開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能夠退出。

5、配置wss

Workerman如何建立一個wss服務,使得客戶端能夠用過wss協來鏈接通信,好比在微信小程序中鏈接服務端。

wss協議實際是 websocket+ SSL,就是在 websocket協議上加入 SSL層,相似 https(http+SSL)。 因此只須要在 websocket協議的基礎上開啓 SSL便可支持 wss協議。
  • 配置方式一:直接用Workerman開啓SSL:

準備工做:

一、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
利用 nginx/apache做爲 wss代理轉發給 workerman注意此方法workerman部分千萬不要設置ssl,不然將沒法鏈接)。
通信原理及流程是:

一、客戶端發起wss鏈接連到nginx/apache

二、nginx/apachewss協議的數據轉換成ws協議數據並轉發到Workermanwebsocket協議端口

三、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在線測試

相關文章
相關標籤/搜索