在TP5中安装GatewayClient拓展,实现主动推送消息到前端页面

首先说明: 环境是在Windows下.

因为项目需要用到websocket协议进行服务端主动推送,所以选择引入GatewayWorker

一.安装GatewayWorker

  下载地址

下载完成后进行解压, 可以看到整个文件夹的目录结构如下所示:

这些文件是个整体, 在Windows下理论上可以放在任何目录中整体运行 start_for_win.bat 脚本.

start_for_win.bat 是 Windows 环境下 GatewayWorker 所有 Worker 进程的启动文件
start.php 是 Linux 环境下 GatewayWorker 所有 Worker 进程的启动文件

二.修改IP:端口与协议

1.start_businessworker.php -> BusinessWorker 进程的启动文件

// bussinessWorker 进程
$worker = new BusinessWorker();
// worker名称
$worker->name = 'YourAppBusinessWorker';
// bussinessWorker进程数量
$worker->count = 4;
// 服务注册地址
$worker->registerAddress = '127.0.0.1:1238';

2.start_gateway.php -> Gateway 进程的启动文件

// gateway 进程,这里使用Text协议,可以用telnet测试
$gateway = new Gateway("Websocket://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';

// 心跳间隔(看需求是否启用心跳包)
// $gateway->pingInterval = 10;
// 心跳数据
// $gateway->pingData = '{"type":"ping"}';

3.tart_register.php -> Register 服务进程的启动文件

// register 必须是text协议
$register = new Register('text://0.0.0.0:1238');

全都正常配置后运行star_for_win.bat, 可以看到如下画面

三.Events.php文件

Events.php 是 BusinessWorker 进程的实际业务处理类
因为在tp中完成所有业务逻辑,GatewayWorker仅仅当做一个单向的推送通道,所以我将Events.php修改如下:

<?php
/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link http://www.workerman.net/
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */

/**
 * 用于检测业务代码死循环或者长时间阻塞等问题
 * 如果发现业务卡死,可以将下面declare打开(去掉//注释),并执行php start.php reload
 * 然后观察一段时间workerman.log看是否有process_timeout异常
 */
//declare(ticks=1);

use \GatewayWorker\Lib\Gateway;

/**
 * 主逻辑
 * 主要是处理 onConnect onMessage onClose 三个方法
 * onConnect 和 onClose 如果不需要可以不用实现并删除
 */
class Events
{
    /**
     * 当客户端连接时触发
     * 如果业务不需此回调可以删除onConnect
     * 
     * @param int $client_id 连接id
     */
    public static function onConnect($client_id)
    {
        // 绑定操作 
        Gateway::sendToClient($client_id, json_encode(array(
            'type'      => 'init',
            'client_id' => $client_id
        )));
    }
    
   /**
    * 当客户端发来消息时触发
    * @param int $client_id 连接id
    * @param mixed $message 具体消息
    */
   public static function onMessage($client_id, $message)
   {
        // 向所有人发送 
        // Gateway::sendToAll("$client_id said $message\r\n");
        //将接收到的json信息转成数组
        $msg = json_decode($message,true);
        //如果数据为空则不处理
        if (!$msg) {
           return;
        }
        //判断消息类型
        switch ($msg['type']) {
            //收到消息
            case 'MessageReceived':
                Gateway::sendToAll(json_encode(['type' => 'MessageReceived','content' => '收到消息']));
                break;
            
            case 'ping':
                Gateway::sendToAll(json_encode(['type' => 'ping','content' => 'Heartbeat']));
                break;
        }
   }
   
   /**
    * 当用户断开连接时触发
    * @param int $client_id 连接id
    */
   public static function onClose($client_id)
   {
       // 向所有人发送 
       // GateWay::sendToAll("$client_id logout\r\n");
   }
}

四.安装GatewayClient拓展

自行安装好composer后
打开cmd切换到项目根目录下, 输入

composer require workerman/gatewayclient

安装完成后, 在需要调用GatewayClient接口的控制器里引用命名空间

use GatewayClient\Gateway;

并设置 Gateway::$registerAddress 属性,告知 GatewayClient 与哪个 GatewayWorker (集群)通讯

Gateway::$registerAddress = '127.0.0.1:1238';

现在, 就可以在我们的项目中调用GatewayClient接口实现各种功能了!

五.TP中控制器主动发送消息部分

<?php

namespace app\index\controller;

use think\Db;
use think\Controller;
use GatewayClient\Gateway;
use think\Request;


class Msg extends Controller
{
    public function _initialize()
    {
        // 设置GatewayWorker服务的Register服务ip和端口,请根据实际情况改成实际值(ip不能是0.0.0.0)
        Gateway::$registerAddress = '127.0.0.1:1238';
    }

    public function index()
    {
        // 这个页面的代码会贴在下一步
        return $this->fetch('msg/index');
    }
   
    // 发送消息
    public function send()
    {
        $param = input();
        // Gateway::$registerAddress  = '127.0.0.1:1238';
        Gateway::sendToAll(json_encode(['type'=>'MessageReceived', 'data'=>$param]));

    }

    // 被访问的测试页面
    public function test()
    {
        $request = Request::instance();
        $url = url('/index/msg/send');
        $url = $request->domain() . $url;
        var_dump($url);
        $data = [
            'aaa' => 111,
            'bbb' => 222
        ];
        $res = get_curl($url, $data);
        // $res = file_get_contents($url);
        var_dump($res);
    }

}

六.index.html测试看结果demo部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    这里只做接收消息展示用, 除了心跳包, 不发送任何消息.
</body>
<script>
    ws = new WebSocket("ws://"+document.domain+":8282");

    ws.onopen = function() {
        console.log("连接成功");
        //10秒发送一次心跳包
        var heart = JSON.stringify({"type":"ping"});
        setInterval(function(){
            ws.send(heart);
        },10000);
    };

    // 服务端主动推送消息时会触发这里的onmessage
    ws.onmessage = function(e){
        // console.log(e);
        var data = eval("("+e.data+")");
        // console.log(data);
        var type = data.type || '';
        // console.log(type);
        switch(type){
            case 'ping':
                console.log('heartbeat');
                break;
            // 当mvc框架调用GatewayClient发消息时直接打印出来
            case 'MessageReceived':
                // 接收到tp中主动发送数据提示的标记
                console.log('MessageReceived', data);
                break;
            
            default :
               console.log(e.data);
        }
    };
</script>
</html>

全都准备就绪之后, 访问 http://domain/index/msg/index (我这里是这个路由, 这里根据自己项目的路由访问)
打开F12, 可以看到 连接成功

再访问发送测试消息的路由, 我这里是 http://solar.cc/index/msg/test, 回到上一步打开的index页面,
可以看到控制台内输出了我们控制器中主动发送的消息

记录一下
-End-

风影OvO

风影OvO, 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA 4.0协议进行授权 | 转载请注明原文链接

留下你的评论

*评论支持代码高亮<pre class="prettyprint linenums">代码</pre>

相关推荐