Laravel6基于Workerman 的Gateway-worker进行长连接通信

1、安装gateway-worker

gateway-worker 它已经引入了 workerman/workerman.

composer require workerman/gateway-worker
composer require workerman/gatewayclient

2. 创建 Workerman 启动文件

创建一个 artisan 命令行工具来启动 Socket 服务端,在 app/Console/Commands 目录下建立命令行文件。

php artisan make:command GatewayWorkerServer

<?php
 
namespace App\Console\Commands;
 
use Illuminate\Console\Command;
use GatewayWorker\BusinessWorker;
use GatewayWorker\Gateway;
use GatewayWorker\Register;
use Workerman\Worker;
 
 
class GatewayWorkerServer extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'workman {action} {--d}';
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Start a Workerman server.';
 
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }
 
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
        global $argv;
        $action = $this->argument('action');
 
        $argv[0] = 'artisan workman';
        $argv[1] = $action;
        $argv[2] = $this->option('d') ? '-d' : '';   //必须是一个-,上面定义命令两个--,后台启动用两个--
 
        $this->start();
    }

  //linux下可以启动三个服务,在windows下可以拆分成三个服务
    private function start()
    {
        $this->startGateWay();
        $this->startBusinessWorker();
        $this->startRegister();
        Worker::runAll();
    }
 
    private function startBusinessWorker()
    {
        $worker                  = new BusinessWorker();
        $worker->name            = 'BusinessWorker';
        $worker->count           = 1;
        $worker->registerAddress = '127.0.0.1:1236';
        $worker->eventHandler    = \App\GatewayWorker\Events::class;
    }
 
    private function startGateWay()
    {
        $gateway = new Gateway("websocket://0.0.0.0:2346");
        $gateway->name                 = 'Gateway';
        $gateway->count                = 1;
        $gateway->lanIp                = '127.0.0.1';
        $gateway->startPort            = 2300;
        $gateway->pingInterval         = 30;
        $gateway->pingNotResponseLimit = 0;
        $gateway->pingData             = '{"type":"ping"}';
        $gateway->registerAddress      = '127.0.0.1:1236';
    }
 
    private function startRegister()
    {
        new Register('text://0.0.0.0:1236');
    }
 
       //php artisan workman start --d  之后    打开浏览器F12 将内容复制到console里return就行
       /* ws = new WebSocket("ws://*.*.*.*:2346");
        ws.onopen = function() {
            ws . send('{"name":"one","user_id":"111"}');
            ws . send('{"name":"two","user_id":"222"}');
        };
        ws.onmessage = function(e) {
            console.log("收到服务端的消息:" + e.data);
        };
        ws.onclose = function(e) {
            console.log("服务已断开" );
        };*/
 
}

相关文档 Gateway类的使用-gateway-worker手册

3. 创建事件监听文件

创建一个 app/GatewayWorker/Events.php 文件来监听处理 workman 的各种事件。

<?php
/**
 * Created by PhpStorm.
 * User: ls
 * Date: 2020/3/25
 * Time: 16:09
 */
namespace App\GatewayWorker;
 
use GatewayWorker\Lib\Gateway;
use Illuminate\Support\Facades\Log;
 
class Events
{
 
    public static function onWorkerStart($businessWorker)
    {
        echo "onWorkerStart\r\n";
    }
 
    public static function onConnect($client_id)
    {
        Gateway::sendToClient($client_id, json_encode(['type' => 'onConnect', 'client_id' => $client_id]));
        echo "onConnect\r\n";
    }
 
    public static function onWebSocketConnect($client_id, $data)
    {
        echo "onWebSocketConnect\r\n";
    }
 
    public static function onMessage($client_id, $message)
    {
        Gateway::sendToClient($client_id, json_encode(['type' => 'onMessage', 'client_id' => $client_id, 'name' => json_decode($message)->name]));
 
        echo "onMessage\r\n";
    }
 
    public static function onClose($client_id)
    {
        Log::info('Workerman close connection' . $client_id);
        echo "onClose\r\n";
    }
 
}

4、测试。 启动 Workerman 服务端

在命令行里面执行,支持的命令大概有 start|stop|restart,其中 --d 的意思是 daemon 模式,后台守护进程

注意,服务中的端口号要加入白名单允许访问

php artisan workman start --d //正式环境开发命令
php artisan workman start  //测试环境开发命令

ls@ls-virtual-machine:/var/www/html/socket/socket$ php artisan workman start --d
Workerman[artisan workman] start in DAEMON mode
-------------------------------------------- WORKERMAN ---------------------------------------------
Workerman version:4.0.2          PHP version:7.2.24-0ubuntu0.18.04.3
--------------------------------------------- WORKERS ----------------------------------------------
proto   user            worker            listen                      processes    status           
tcp     ls              Gateway           websocket://0.0.0.0:2346    1             [OK]            
tcp     ls              BusinessWorker    none                        1             [OK]            
tcp     ls              Register          text://0.0.0.0:1236         1             [OK]            
----------------------------------------------------------------------------------------------------
Input "php artisan workman stop" to stop. Start success.

在浏览器 F12 打开调试模式,在 Console 里输入

ws = new WebSocket("ws://*.*.*.*:2346");
    ws.onopen = function() {
        ws . send('{"name":"one","user_id":"111"}');
        ws . send('{"name":"two","user_id":"222"}');
    };
    ws.onmessage = function(e) {
        console.log("收到服务端的消息:" + e.data);
    };
    ws.onclose = function(e) {
        console.log("服务已断开" );
    }

5、http升级https时,websocket注意事项

场景:做系统升级的时候前端有用到websocket做数据实时更新,之前用的websocket连接时ip加端口模式:

var ws = new WebSocket("ws://127.0.0.1:12151");这种模式是正常访问的,但当项目的访问从http升级到https的时候,发现websocket连接不上了,报错了。

解决方法:查阅文档发现websocket的连接有2种方式

var ws = new WebSocket("ws://192.163.10.63:12151/socket")
 
var ws = new WebSocket("wss://域名/socket/")

注意点:

  1. 如果网站使用HTTPS,WebSocket必须要使用wss协议;
  2. 使用wss协议的连接请求必须只能写域名,而非IP+端口;
  3. 建议在URL域名后面为websocket定义一个路径,本例中是/socket/

nginx配置

只需要在HTTPS配置的server内加一个location即可

# websockets
    location /socket/ {
        proxy_pass http://127.0.0.1:12151;  
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }

如下图

 

 

注意:

  1、location /socket/ {...}这里要格外注意!

    html中的url是 wss://http://www.aabb.com/socket/,所以Nginx配置中一定要是 /socket/

    如果前端是 wss://http://www.aabb.com/socket,Nginx对应是 /socket

  2、proxy_pass对应的最好是公网IP加端口号, 'localhost:12151','127.0.0.1:12151'

  3、proxy_http_version 1.1 版本号必须是1.1,这条配置必需

说明:Nginx反向代理,无论是HTTP/S或是WebSocket都会走443端口,由Nginx分发给各个项目服务器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值