Lumen/Laravel 集成 GatewayWorker (Workerman),实现简单的聊天系统.

GatewayWorker 与 Workerman 的关系
Workerman 相比 GatewayWorker 也更底层,需要开发者有一定的多进程编程经验。因为绝大多数开发者的目标是基于 Workerman 开发 TCP 长连接应用,而长连接应用服务端有很多共同之处,例如它们有相同的进程模型以及单发、群发、广播等接口需求。所以才有了 GatewayWorker 框架,GatewayWorker 是基于 Workerman 开发的一个 TCP 长连接框架,实现了单发、群送、广播等长连接必用的接口。GatewayWorker 框架实现了 Gateway Worker 进程模型,天然支持分布式多服务器部署,扩容缩容非常方便,能够应对海量并发连接。可以说 GatewayWorker 是基于 Workerman 实现的一个更完善的专门用于实现 TCP 长连接的项目框架。项目是长连接并且需要客户端与客户端之间通讯,建议使用 GatewayWorker。

Step1. 引入包
在 composer.json 件的 require 引入这三行

 "workerman/gateway-worker": "^3.0",
 "workerman/gatewayclient": "^3.0",
 "workerman/workerman": "^3.5"

终端的项目根目录输入 composer update
Step2. 创建一个 Command
在 App\Console\Commands 目录创建 GatewayWorkerServer.php 文件,作为服务端口的启动文件

<?php

namespace App\Console\Commands;

use GatewayWorker\BusinessWorker;
use Illuminate\Console\Command;
use Workerman\Worker;
use GatewayWorker\Gateway;
use GatewayWorker\Register;

class GatewayWorkerServer extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'gateway-worker:server {action} {--daemon}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Start a GatewayWorker Server.';

    /**
     * constructor
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * [@return](https://learnku.com/users/31554) mixed
     */
    public function handle()
    {
        global $argv;

        if (!in_array($action = $this->argument('action'), ['start', 'stop', 'restart'])) {
            $this->error('Error Arguments');
            exit;
        }

        $argv[0] = 'gateway-worker:server';
        $argv[1] = $action;
        $argv[2] = $this->option('daemon') ? '-d' : '';

        $this->start();
    }

    private function start()
    {
        $this->startGateWay();
        $this->startBusinessWorker();
        $this->startRegister();
        Worker::runAll();
    }

    private function startBusinessWorker()
    {
        $worker                  = new BusinessWorker();
        $worker->name            = 'BusinessWorker';                        #设置BusinessWorker进程的名称
        $worker->count           = 1;                                       #设置BusinessWorker进程的数量
        $worker->registerAddress = '127.0.0.1:12360';                        #注册服务地址
        $worker->eventHandler    = \App\GatewayWorker\Events::class;            #设置使用哪个类来处理业务,业务类至少要实现onMessage静态方法,onConnect和onClose静态方法可以不用实现
    }

    private function startGateWay()
    {
        $gateway = new Gateway("websocket://0.0.0.0:23460");
        $gateway->name                 = 'Gateway';                         #设置Gateway进程的名称,方便status命令中查看统计
        $gateway->count                = 1;                                 #进程的数量
        $gateway->lanIp                = '127.0.0.1';                       #内网ip,多服务器分布式部署的时候需要填写真实的内网ip
        $gateway->startPort            = 2300;                              #监听本机端口的起始端口
        $gateway->pingInterval         = 30;
        $gateway->pingNotResponseLimit = 0;                                 #服务端主动发送心跳
        $gateway->pingData             = '{"mode":"heart"}';
        $gateway->registerAddress      = '127.0.0.1:12360';                  #注册服务地址
    }

    private function startRegister()
    {
        new Register('text://0.0.0.0:12360');
    }

}

//ws = new WebSocket("ws://127.0.0.1:23460");
//ws.onopen = function() {
//    ws . send('{"mode":"say","order_id":"21",type:1,"content":"文字内容","user_id":21}');
//    ws . send('{"mode":"chats","order_id":"97"}');
//};
//ws.onmessage = function(e) {
//    console.log("收到服务端的消息:" + e.data);
//};

在 App\Console\Kernel 引入 GatewayWorkerServer::class

Step3. 创建监听文件
在 app 目录下创建 GatewayWorker/Events.php 文件

<?php

namespace App\GatewayWorker;

use App\Models\Home\Order;
use App\Models\Home\OrderChat;
use GatewayWorker\Lib\Gateway;
use Illuminate\Support\Facades\Log;
use mysql_xdevapi\Exception;

class Events
{

    public static function onWorkerStart($businessWorker)
    {
        echo "BusinessWorker    Start\n";
    }

    public static function onConnect($client_id)
    {
        Gateway::sendToClient($client_id, json_encode(['type' => 'init', 'client_id' => $client_id]));
    }

    public static function onWebSocketConnect($client_id, $data)
    {

    }

    public static function onMessage($client_id, $message)
    {
        $response = ['errcode' => 0, 'msg' => 'ok', 'data' => []];
        $message = json_decode($message);

        if (!isset($message->mode)) {
            $response['msg'] = 'missing parameter mode';
            $response['errcode'] = ERROR_CHAT;
            Gateway::sendToClient($client_id, json_encode($response));
            return false;
        }

        switch ($message->mode) {
            case 'say':   #处理发送的聊天
                if (self::authentication($message->order_id, $message->user_id)) {
                    OrderChat::store($message->order_id, $message->type, $message->content, $message->user_id);
                } else {
                    $response['msg'] = 'Authentication failure';
                    $response['errcode'] = ERROR_CHAT;
                }
                break;
            case 'chats':  #获取聊天列表
                $chats = OrderChat::where('order_id', $message->order_id)->get();
                $response['data'] = ['chats' => $chats];
                break;
            default:
                $response['errcode'] = ERROR_CHAT;
                $response['msg'] = 'Undefined';
        }

        Gateway::sendToClient($client_id, json_encode($response));
    }

    public static function onClose($client_id)
    {
        Log::info('close connection' . $client_id);
    }

    private static function authentication($order_id, $user_id): bool
    {
        $order = Order::find($order_id);
        if (is_null($order)) {
            return false;
        }
        return in_array($user_id, [$order->user_id, $order->to_user_id]) ? true : false;   #判断属不属于这个订单的两个人
    }
}

注意 GatewayWorkerServer.php 文件中的 startBusinessWorker 方法中 $worker->eventHandler 属性的路径是 Event.php 的路径,namespace 可以自己定义

最后执行一个 composer dump-autoload

Step4 测试
开启服务,在终端输入
php artisan gateway-worker:server start

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

ws = new WebSocket("ws://127.0.0.1:23460");
ws = new WebSocket("ws://127.0.0.1:23460");
ws.onopen = function() {
    ws . send('{"mode":"say","order_id":"375","type":1,"content":"你好","user_id":100036}');
    ws . send('{"mode":"chats","order_id":"375"}');
};
ws.onmessage = function(e) {
    console.log("收到服务端的消息:" + e.data);
};

简单实现订单里的买家和卖家交流、获取聊天记录,也可以把相关的信息存到缓存里,
在 public static function onMessage() 里修改自己的业务逻辑

http://doc2.workerman.net/ GatewayWorker2.x 3.x 手册

————————————————
原文作者:summer-1994
转自链接:https://learnku.com/articles/25208

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值