使用GatewayWorker,开启wss,并设置获取真实ip后,onConnect回调函数中设置的$_SESSION值,在onMessage中获取不到

BBQ

composer下载的GatewayWorker,
按照手册配置nginx创建wss连接,
http://doc2.workerman.net/326160
并且按照手册中 - 透过nginx代理获取客户端真实ip http://doc.workerman.net/faq/get-real-ip-from-proxy.html
一切配置完之后,项目正常启动和链接,并且真实IP也能获取
按照手册中,关闭未认证连接
截图
测试1000个连接,只能链接990左右,剩下几个,都是因为在onMessage中没有获取到onConnect中设置的$_SESSION['auth_timer_id']

关闭获取真实ip这段代码,1000个链接测试全部能连上,每种情况各测3次,得到的结果是,开启获取真实ip就部分连不上,关了正常连接

下有详细配置

测试结果

开启获取真实ip

截图
使用workerman测试链接
测试文件运行结果
截图
连接量
截图
错误日志文件
截图
status运行状态
截图

关闭获取真实ip

截图
测试文件运行结果
截图
连接量
截图
由于1000个链接全部成功,所以没有产生错误日志

status运行状态
截图

环境

宝塔 php7.2+nginx+thinkphp5.0

nginx站点配置

截图

wss配置

截图

GatewayWorker配置

截图

处理业务逻辑Event.php

class Events
{
    /**
     * 当客户端连接上gateway进程时(TCP三次握手完毕时)触发的回调函数。
     */
    public static function onConnect($client_id)
    {
        //连接到来后,定时10秒关闭这个链接,需要10秒内发认证并删除定时器阻止关闭连接的执行
        $auth_timer_id = Timer::add(10, function ($client_id) {
            Gateway::sendToCurrentClient(json_encode(['type' => 'logout', 'data' => '登录错误']));
            Gateway::closeClient($client_id);
        }, array($client_id), false);
        $_SESSION['auth_timer_id'] = $auth_timer_id;
        $data = [
            'type' => 'sys',
            'data' => '连接成功',
            'time' => time()
        ];
        Gateway::sendToCurrentClient(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }

    /**
     * 有消息时
     * @param int $client_id
     * @param mixed $message
     */
    public static function onMessage($client_id, $message)
    {
        $message_data = json_decode($message, true);
        if (!$message_data) {
            return;
        }
        switch ($message_data['type']) {
            case 'pong':
                Gateway::sendToCurrentClient(json_encode($message_data));
                break;
            case 'ceshilogin':
                if (empty($_SESSION['auth_timer_id'])) {
                    file_put_contents('$session.txt',json_encode(['$client_id'=>$client_id,'session'=>$_SESSION,'type'=>'onmessage'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES). '-' . date("Y-m-d H:i:s", time()) . PHP_EOL. PHP_EOL, FILE_APPEND);
                    Gateway::sendToCurrentClient(json_encode(['type' => 'logout', 'msg' => 'auth_timer_id不存在', 'data' => $_SESSION]));
                    Gateway::closeClient($client_id);
                    return false;
                }
                Timer::del($_SESSION['auth_timer_id']);
                Gateway::updateSession($client_id, ['username' => 'app-' . $message_data['username']]);
                Gateway::bindUid($client_id, 'app-' . $message_data['username']);
                $data = [
                    'type' => 'joins',
                    'data' => '[app-' . $message_data['username'] . "]加入成功\n",
                    'c_id' => $client_id
                ];
                Gateway::sendToCurrentClient(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
                break;
            default:
                Gateway::sendToCurrentClient($message);
        }
    }

    /**
     * 当客户端断开连接时
     * @param integer $client_id 客户端id
     */
    public static function onClose($client_id)
    {
        $username = isset($_SESSION['username']) ? $_SESSION['username'] : $client_id;
        $data = [
            'type' => 'sys',
            'userinfo' => Gateway::getSession($client_id),
            'data' => '[' . $username . "]-已退出\n",
            'reip' => isset($_SESSION['realIP']) ? $_SESSION['realIP'] : null
        ];
        Gateway::sendToUid('测试账号', json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }
}

workerman测试连接代码

<?php

use Workerman\Worker;
use Workerman\Lib\Timer;
use Workerman\Connection\AsyncTcpConnection;

require_once __DIR__ . '/vendor/workerman/workerman/Autoloader.php';

$worker = new Worker();
$worker->onWorkerStart = 'connect';
function connect()
{
    static $count = 0;
    // 2000个链接
    if ($count++ >= 1000) return;
    // 建立异步链接
    $con = new AsyncTcpConnection("ws://xxx.xxx.cn/tb:443");
    $con->transport = 'ssl';
    $con->onConnect = function ($con) {
        // 递归调用connect
        connect();
    };
    // 远程websocket服务器发来消息时
    $con->onMessage = function ($con, $msg) {
        echo "$msg\n";
        $message_data = json_decode($msg, true);
        if (!empty($message_data) && is_array($message_data)) {
            if (isset($message_data['data']) && $message_data['data'] == '连接成功'){
                $data=['type' => 'ceshilogin', 'username' => '测试用户'.mt_rand()];
                $con->send(json_encode($data));
                echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)."\n";
            }
        }
    };
    // 当连接远程websocket服务器的连接断开时
    $con->onClose = function ($con) {
        echo "con close\n";
    };
    // 连接上发生错误时,一般是连接远程websocket服务器失败错误
    $con->onError = function ($con, $code, $msg) {
        echo "error: " . $code . "--" . $msg . "\n";
    };
    // 当前链接每10秒发个心跳包
    Timer::add(10, function () use ($con) {
        $ping = array(
            'type' => 'pong',
            'data' => array()
        );
        $con->send(json_encode($ping));
    });
    $con->connect();
    echo $count, " connections complete\n";
}

Worker::runAll();

查看连接量代码

Gateway::$registerAddress = '127.0.0.1:2345';
        $getsession = Gateway::getAllClientSessions();
        $data = [
            'user_count' => Gateway::getAllClientIdCount(),
            'user_list' => $getsession
        ];
        $this->success('ok', $data);

因为获取不到session里面的定时任务id,导致连接的时候直接被踢掉,而且有时候,exe软件端连 域名/wss 会有连不上的情况,改成 ip:端口 又可以连接,浏览器端不会有这种问题
请问这是什么问题呢?希望大佬解答

1662 2 0
2个回答

walkor

打开 vendor/workerman/gateway-worker/src/Gateway.php,看下Gateway版本号。

  • BBQ 2021-01-27

    const VERSION = '3.0.18';

  • BBQ 2021-01-27

    这个$_SESSION对版本号要求吗?

walkor

感谢你这么详细的提问。
这个可能是gatewayWorker的一个bug。
现在gatewayWorker已经支持在Events.php中设置onWebSocketConnect回调了,所以不需要在 start_gateway.php 里加设置真实ip的代码了,你可以把这部分代码放到Events.php里了。

代码类似:

class Events
{

   public static function onWebsocketConnect($client_id, $data)
   {    
        $_SESSION['realIP'] = isset($data['server']['HTTP_X_REAL_IP']) ? $data['server']['HTTP_X_REAL_IP'] : '127.0.0.1';
   }

}

然后删除 start_gateway.php 里 $gateway->onConnect 和 $gateway->onWebsocketConnect 的相关代码完全重启gatewayWorker试下。

  • BBQ 2021-01-27

    好的,我再试一下

  • BBQ 2021-01-27

    加入之后,果然好了,分别测了1000次和1500次(由于测试服务器内存太低,连到1500左右就卡住不动了),均连接成功,并且返回真实ip没有错误日志产生。
    大佬,请问下,如果后期Worker业务层做了分布式,会因为不同服务器导致类似这种session获取不到的问题吗?

  • walkor 2021-01-28

    不会。

  • laogouWorker 2021-01-28

    @1:我docker环境的获取到的都是127.0.0.1

年代过于久远,无法发表回答
🔝