ThinkPHP部署Workerman的成功使用示例

目录

本文介绍thinkphp中关于composer集成workerman的方法,并解决了安装过程 中遇到的错误,实现了和woerkman进行握手和通信的demo。用户可以在此基础上按自己的逻辑实现一个聊天系统或者客服系统。

一、安装扩展包   composer require topthink/think-worker

直接执行:composer require topthink/think-worker=1.0.*     即可成功

二、新建 server.php

#!/usr/bin/env php
<?php
define(\'APP_PATH\', __DIR__ . \'/application/\');
define(\'BIND_MODULE\',\'push/Worker\');
// 加载框架引导文件
require __DIR__ . \'/thinkphp/start.php\';

三、新建Worker.php    

php think make:controller push/Worker

即可,将里面的内容替换如下所示:

<?php
namespace app\\push\\controller;
use think\\Controller;
use think\\Request;
use think\\worker\\Server;
use think\\Cache;
class Worker extends Server
{
    protected $socket = \'websocket://0.0.0.0:2346\';
    protected $processes = 1;
    protected $uidConnections = array();
    static $count  = 0;
    /**
     * 收到信息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data)
    {
        $retdata=json_decode($data,true);
        $uid=$retdata[\'id\'];
        $message=$retdata[\'msg\'];
        if(isset($this->uidConnections[$uid]))
        {
            $connection = $this->uidConnections[$uid];
            $connection->send($message);
            // return true;
        }
        $connection->send(\'我收到你的信息了333=\'.$retdata[\'msg\']);
    }
    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
    {
        $this->uidConnections[$connection->id] = $connection;
        $connection->send(\'你连接了我=\'.$connection->id);
    }
    // 针对uid推送数据
    public function sendMessageByUid($uid, $message)
    {
        if(isset($this->uidConnections[$uid]))
        {
            $connection = $this->uidConnections[$uid];
            $connection->send($message);
            return true;
        }
        return false;
    }
    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection)
    {
    }
    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        echo \"error $code $msg\\n\";
    }
    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
    }
}

四、执行 php server.php start

遇到禁用函数就去对应的PHP里面把禁用函数删除 (此命令可以放到Supervisor的守护进程里面去),并且查看端口是否运行,宝塔里面也要放行对应的端口 2346

测试远程连接: telnet localhost 2346         localhost改成外网ip即可,这个走通了,前端就能直接连接了

linux 退出Telnet命令    先输入命令:CTRL+]然后再输入命令:quit

五、前端代码

<!DOCTYPE html>
<html lang=\"en\">
<head>
    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
    <title>Title</title>
</head>
<body>
<script>
    ws = new WebSocket(\"ws://118.**.***.207:2346\");
    ws.onopen = function() {
        console.log(\"连接成功\");
        ws.send(\'tom\');
        console.log(\"给服务端发送一个字符串:tom\");
    };
    ws.onmessage = function(e) {
        console.log(\"收到服务端的消息:\" + e.data);
    };
</script>
</body>
</html>

六、前端开两个端口即可进行相互通讯:

ws.send(\'{\"id\":\"2\",\"msg\":\"21111111111110\"}\');

重点在这:因为在这里需要用到服务端给客户端推送,用到了text服务

WorkerMan中php后端及时推送消息给客户端

原理:

1、建立一个websocket Worker,用来维持客户端长连接

2、websocket Worker内部建立一个text Worker

3、websocket Worker 与 text Worker是同一个进程,可以方便的共享客户端连接

4、某个独立的php后台系统通过text协议与text Worker通讯

5、text Worker操作websocket连接完成数据推送

代码及步骤

//push.php
<?php
use Workerman\\Worker;
require_once \'./vendor/workerman/workerman/Autoloader.php\';
// 初始化一个worker容器,监听1234端口
$worker = new Worker(\'websocket://0.0.0.0:1234\');//
/*
 * 注意这里进程数必须设置为1,否则会报端口占用错误
 * (php 7可以设置进程数大于1,前提是$inner_text_worker->reusePort=true)
 */
$worker->count = 1;
// worker进程启动后创建一个text Worker以便打开一个内部通讯端口
$worker->onWorkerStart = function($worker)
{
    // 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符
    $inner_text_worker = new Worker(\'text://0.0.0.0:5678\');
    $inner_text_worker->onMessage = function($connection, $buffer)
    {
        // $data数组格式,里面有uid,表示向那个uid的页面推送数据
        $data = json_decode($buffer, true);
        $uid = $data[\'uid\'];
        // 通过workerman,向uid的页面推送数据
        $ret = sendMessageByUid($uid, $buffer);
        // 返回推送结果
        $connection->send($ret ? \'ok\' : \'fail\');
    };
    // $connection->send(\'你好,你连接我了\');
    // ## 执行监听 ##
    $inner_text_worker->listen();
};
// 新增加一个属性,用来保存uid到connection的映射
$worker->uidConnections = array();
// 当有客户端发来消息时执行的回调函数
$worker->onMessage = function($connection, $data)
{
    $data=json_decode($data,true);
    $connection->send(\'99897\');
    global $worker;
    // 判断当前客户端是否已经验证,既是否设置了uid
    if(!isset($connection->uid))
    {
        // 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证)
        $connection->uid = $data[\'id\'];
        /* 保存uid到connection的映射,这样可以方便的通过uid查找connection,
         * 实现针对特定uid推送数据
         */
        $worker->uidConnections[$connection->uid] = $connection;
        $connection->send(\'9980\'.$data[\'msg\']);
        return;
    }else{
         $connection->send(\'998123\');
    }
};
// 当有客户端连接断开时
$worker->onClose = function($connection)
{
    global $worker;
    if(isset($connection->uid))
    {
        // 连接断开时删除映射
        unset($worker->uidConnections[$connection->uid]);
    }
};
// 向所有验证的用户推送数据
function broadcast($message)
{
    global $worker;
    foreach($worker->uidConnections as $connection)
    {
        $connection->send($message);
    }
}
// 针对uid推送数据
function sendMessageByUid($uid, $message)
{
    global $worker;
    if(isset($worker->uidConnections[$uid]))
    {
        $connection = $worker->uidConnections[$uid];
        $connection->send($message);
        return true;
    }
    return false;
}

运行所有的worker

Worker::runAll();
启动后端服务 php push.php start -d

前端接收推送的js代码

<!DOCTYPE html>
<html lang=\"en\">
<head>
    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
    <title>Title</title>
</head>
<body>
<script>
    var ws = new WebSocket(\'ws://118.**.**.207:1234\');
    ws.onopen = function(){
        var uid = \'uid1\';
        ws.send(uid);
        console.log(\"给服务端发送一个字符串:\"+uid);
    };
    ws.onmessage = function(e){
        // alert(e.data);
        console.log(\"收到服务端的消息:\" + e.data);
    };
</script>
</body>
</html>

后端推送消息的代码

// 建立socket连接到内部推送端口
$client = stream_socket_client(\'tcp://127.0.0.1:5678\', $errno, $errmsg, 1);
// 推送的数据,包含uid字段,表示是给这个uid推送
$data = array(\'uid\'=>\'uid1\', \'percent\'=>\'88%\');
// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符
fwrite($client, json_encode($data).\"\\n\");
// 读取推送结果
echo fread($client, 8192);

后端推送消息的代码和push.php监听同一个端口

push.php和前端监听同一个websocket端口

通过后端推送消息的代码向push.php推送数据,

push.php接受到数据后通过处理 利用websocket往前端推送数据

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容