Linux上搭建并使用 thinkphp + Workerman + Gateway

1.使用 composer 安装

composer require workerman/workerman-for-win
composer require workerman/gateway-worker-for-win

2.构造启动方法 Gate.php,命名空间根据位置自己的文件位置调整。

其中 $worker->eventHandler 参数填写的是逻辑文件的地址,逻辑文件创建在下一步

<?php 
/**
 * linux workerman例子测试
 */
namespace app\common\controller;

use think\Env;
use Workerman\Worker;
use GatewayWorker\Gateway;
use GatewayWorker\Register;
use GatewayWorker\BusinessWorker;

class Gate
{
    /**
     * 构造函数
     * @access public
     */
    public function __construct(){
        
        //初始化各个GatewayWorker
        //初始化register register 服务必须是text协议
        $register = new Register('text://0.0.0.0:1236');
    
        //初始化 bussinessWorker 进程
        $worker = new BusinessWorker();
        // worker名称
        $worker->name = 'ChatBusinessWorker';
        // bussinessWorker进程数量
        $worker->count = 4;
        // 服务注册地址
        $worker->registerAddress = '127.0.0.1:1236';
        //设置处理业务的类,此处制定Events的命名空间
        $worker->eventHandler = 'app\common\socket\Workerman';
        // 初始化 gateway 进程
        $gateway = new Gateway("websocket://".Env::get('socket.host', '0.0.0.0').":".Env::get('socket.port', '9004'));
        // 设置名称,方便status时查看
        $gateway->name = 'ChatGateway';
        $gateway->count = 4;
        // 分布式部署时请设置成内网ip(非127.0.0.1)
        $gateway->lanIp = '127.0.0.1';
        // 内部通讯起始端口,假如$gateway->count=4,起始端口为4000
        // 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口
        $gateway->startPort = 2300;
        // 心跳间隔
        $gateway->pingInterval = 10;
        // 心跳数据
        $gateway->pingData = '{"a":1,"d":"pong","t":1}';
        // 服务注册地址
        $gateway->registerAddress = '127.0.0.1:1236';
    
        //运行所有Worker;
        Worker::runAll();
    }
}

3.创建逻辑执行文件 Workerman.php,同样的命名空间根据位置修改。

其他推送消息给个人、推送消息给某个组、用户加入某个组、绑定client_id和uid 等方法均在类GatewayWorker\Lib\Gateway里面。文档可以参考 http://doc2.workerman.net/on-messsge.html

<?php

namespace app\common\socket;

use think\Env;
use Exception;
use Workerman\Worker;
use Workerman\Lib\Timer;
use GatewayWorker\Lib\Gateway;

class Workerman
{
    /**
     * 消息处理
     * @param int $client_id
     * @param mixed $message
     */
    public static function onMessage($client_id, $message)
    {
        try {
            // 客户端传递的是json数据
            self::handle_message($client_id, $message);
        } catch (Exception $e) {
            return Gateway::sendToCurrentClient('请求数据不正确');
        }
    }

    /**
     * 当客户端断开连接时
     * @param integer $client_id 客户端id
     */
    public static function onClose($client_id)
    {
        // debug
        echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:{$client_id} onClose:''\n";

        
    }

    /**
     * 定时推送
     *
     * @param [type] $worker
     * @return void
     */
    public static function onWorkerStart($worker)
    {
        Timer::add(1, function() use($worker) {
            
        });
    }

    /**
     * 客户端消息处理
     *
     * @param [type] $client_id
     * @param string $data
     * @return void
     */
    protected static function handle_message($client_id, $data)
    {
        $param = json_decode($data, true);
        
        // TODO 处理数据
    }
}

需要注意长连接,容易出现数据库连接中断的问题,报错 mysql has gone away,可以在定时任务中每30秒执行一次查询来解决数据库断开的问题

4.最后创建启动文件 gateway.php 放在根目录

<?php
/**
 * 此文件只能在Linux运行
 */
ini_set('display_errors', 'on');

if(strpos(strtolower(PHP_OS), 'win') === 0)
{
    exit("not support windows.\n");
}
//检查扩展
if(!extension_loaded('pcntl'))
{
    exit("Please install pcntl extension");
}
if(!extension_loaded('posix'))
{
    exit("Please install posix extension");
}
define('APP_PATH', __DIR__ . '/application/');
define('BIND_MODULE','common/Gate');

// 加载框架引导文件
require __DIR__ . '/thinkphp/start.php';

5.启动命令

php gateway.php start
php gateway.php start -d 守护进程

6.(可选)监听文件 listen.sh 主要作用是在 workerman 主进程崩溃之后,重启进程

创建 listen.sh 在根目录,写入内容。添加到 linux 的定时任务中 ,/home/wwwroot/project 替换成自己的项目路径

#! /bin/bash
cd /home/wwwroot/live;

# need to listen process
process=('WorkerMan: master');
# exec process action
actions=('php /home/wwwroot/project/gateway.php start -d');

for((i=0;i<"${#process[@]}";i++))
do
    pid=$(ps aux | grep "${process[i]}" | grep -v grep | awk '{print $2}');
    if [ "${pid}" == '' ] && [ "${actions[i]}" != '' ]; then
        eval "${actions[i]}";
    fi
done;

写入定时任务的流程

# 编辑定时任务,没有crontab的话百度自行安装
crontab -e 
# 输入
* * * * sh /home/wwwroot/project/listen.sh > /dev/null 2>&1
# 然后保存
:wq
# 查看是否保存成功
crontab -l

评论已关闭。