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就部分连不上,关了正常连接
下有详细配置
使用workerman测试链接
测试文件运行结果
连接量
错误日志文件
status运行状态
测试文件运行结果
连接量
由于1000个链接全部成功,所以没有产生错误日志
status运行状态
宝塔 php7.2+nginx+thinkphp5.0
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));
}
}
<?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:端口 又可以连接,浏览器端不会有这种问题
请问这是什么问题呢?希望大佬解答
打开 vendor/workerman/gateway-worker/src/Gateway.php,看下Gateway版本号。
const VERSION = '3.0.18';
这个$_SESSION对版本号要求吗?
感谢你这么详细的提问。
这个可能是gatewayWorker的一个bug。
现在gatewayWorker已经支持在Events.php中设置onWebSocketConnect回调了,所以不需要在 start_gateway.php 里加设置真实ip的代码了,你可以把这部分代码放到Events.php里了。
代码类似:
然后删除 start_gateway.php 里 $gateway->onConnect 和 $gateway->onWebsocketConnect 的相关代码完全重启gatewayWorker试下。
好的,我再试一下
加入之后,果然好了,分别测了1000次和1500次(由于测试服务器内存太低,连到1500左右就卡住不动了),均连接成功,并且返回真实ip没有错误日志产生。
大佬,请问下,如果后期Worker业务层做了分布式,会因为不同服务器导致类似这种session获取不到的问题吗?
不会。
@1:我docker环境的获取到的都是127.0.0.1