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

0

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' => '' . $message_data['username']]);
Gateway::bindUid($client_id, '' . $message_data['username']);
$data = [
'type' => 'joins',
'data' => '[' . $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:端口 又可以连接,浏览器端不会有这种问题
请问这是什么问题呢?希望大佬解答

已邀请:

walkor

赞同来自: tgzmos BBQ

感谢你这么详细的提问。
这个可能是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试下。

walkor

赞同来自:

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

要回复问题请先登录注册