composer下載的GatewayWorker,
按照手冊(cè)配置nginx創(chuàng)建wss連接,
http://doc2.workerman.net/326160
并且按照手冊(cè)中 - 透過(guò)nginx代理獲取客戶端真實(shí)ip http://doc.workerman.net/faq/get-real-ip-from-proxy.html
一切配置完之后,項(xiàng)目正常啟動(dòng)和鏈接,并且真實(shí)IP也能獲取
按照手冊(cè)中,關(guān)閉未認(rèn)證連接
測(cè)試1000個(gè)連接,只能鏈接990左右,剩下幾個(gè),都是因?yàn)樵趏nMessage中沒(méi)有獲取到onConnect中設(shè)置的$_SESSION['auth_timer_id']
關(guān)閉獲取真實(shí)ip這段代碼,1000個(gè)鏈接測(cè)試全部能連上,每種情況各測(cè)3次,得到的結(jié)果是,開(kāi)啟獲取真實(shí)ip就部分連不上,關(guān)了正常連接
下有詳細(xì)配置
使用workerman測(cè)試鏈接
測(cè)試文件運(yùn)行結(jié)果
連接量
錯(cuò)誤日志文件
status運(yùn)行狀態(tài)
測(cè)試文件運(yùn)行結(jié)果
連接量
由于1000個(gè)鏈接全部成功,所以沒(méi)有產(chǎn)生錯(cuò)誤日志
status運(yùn)行狀態(tài)
寶塔 php7.2+nginx+thinkphp5.0
class Events
{
/**
* 當(dāng)客戶端連接上gateway進(jìn)程時(shí)(TCP三次握手完畢時(shí))觸發(fā)的回調(diào)函數(shù)。
*/
public static function onConnect($client_id)
{
//連接到來(lái)后,定時(shí)10秒關(guān)閉這個(gè)鏈接,需要10秒內(nèi)發(fā)認(rèn)證并刪除定時(shí)器阻止關(guān)閉連接的執(zhí)行
$auth_timer_id = Timer::add(10, function ($client_id) {
Gateway::sendToCurrentClient(json_encode(['type' => 'logout', 'data' => '登錄錯(cuò)誤']));
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));
}
/**
* 有消息時(shí)
* @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);
}
}
/**
* 當(dāng)客戶端斷開(kāi)連接時(shí)
* @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('測(cè)試賬號(hào)', 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個(gè)鏈接
if ($count++ >= 1000) return;
// 建立異步鏈接
$con = new AsyncTcpConnection("ws://xxx.xxx.cn/tb:443");
$con->transport = 'ssl';
$con->onConnect = function ($con) {
// 遞歸調(diào)用connect
connect();
};
// 遠(yuǎn)程websocket服務(wù)器發(fā)來(lái)消息時(shí)
$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' => '測(cè)試用戶'.mt_rand()];
$con->send(json_encode($data));
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)."\n";
}
}
};
// 當(dāng)連接遠(yuǎn)程websocket服務(wù)器的連接斷開(kāi)時(shí)
$con->onClose = function ($con) {
echo "con close\n";
};
// 連接上發(fā)生錯(cuò)誤時(shí),一般是連接遠(yuǎn)程websocket服務(wù)器失敗錯(cuò)誤
$con->onError = function ($con, $code, $msg) {
echo "error: " . $code . "--" . $msg . "\n";
};
// 當(dāng)前鏈接每10秒發(fā)個(gè)心跳包
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);
因?yàn)楂@取不到session里面的定時(shí)任務(wù)id,導(dǎo)致連接的時(shí)候直接被踢掉,而且有時(shí)候,exe軟件端連 域名/wss 會(huì)有連不上的情況,改成 ip:端口 又可以連接,瀏覽器端不會(huì)有這種問(wèn)題
請(qǐng)問(wèn)這是什么問(wèn)題呢?希望大佬解答
感謝你這么詳細(xì)的提問(wèn)。
這個(gè)可能是gatewayWorker的一個(gè)bug。
現(xiàn)在gatewayWorker已經(jīng)支持在Events.php中設(shè)置onWebSocketConnect回調(diào)了,所以不需要在 start_gateway.php 里加設(shè)置真實(shí)ip的代碼了,你可以把這部分代碼放到Events.php里了。
代碼類(lèi)似:
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 的相關(guān)代碼完全重啟gatewayWorker試下。
加入之后,果然好了,分別測(cè)了1000次和1500次(由于測(cè)試服務(wù)器內(nèi)存太低,連到1500左右就卡住不動(dòng)了),均連接成功,并且返回真實(shí)ip沒(méi)有錯(cuò)誤日志產(chǎn)生。
大佬,請(qǐng)問(wèn)下,如果后期Worker業(yè)務(wù)層做了分布式,會(huì)因?yàn)椴煌?wù)器導(dǎo)致類(lèi)似這種session獲取不到的問(wèn)題嗎?