gateway-worker向uid发送消息前,如何判断uid是否已离线?

一、问题描述

我有一个场景,像是车场道闸那种收费系统
1.gateway-worker作为服务端,然后道闸系统是客户端,与服务端建立tcp长连接。(客户端会向服务端发送心跳,5s/次)
2.用户请求服务端,获取道闸上的金额,进行支付
3.支付完,道闸抬杆车辆驶离

车场道闸连接模型 (1).jpg

假设道闸客户端连接到gateway-worker的client_id是001,车场的客户端编号是A,那在客户端连接上服务端的时候,会进行client_id 001和编号A的绑定Gateway::bindUid(001, 'A')。那后续有用户发起http请求获取金额的时候,请求中也会传递车场编号A,那服务端会向客户端A发送tcp请求获取金额,代码示例Gateway::sendToUid('A', json_encode($message));

二、问题出现的环境背景及自己尝试过哪些方法

现在有一种情况,就是道闸系统有时候网络不好,老是断网,断网情况下,道闸客户端就没办法及时向服务端及时发送心跳包,服务端也不知道这个客户端A离线了,这时候如果有http请求进来,服务端会继续向客户端A发送请求获取金额,这时候就会导致进程阻塞,导致http请求一直在请求中,直接影响到后续的http请求也进不来

2.1 尝试的方案

1、在向客户端A发送请求前,检测客户端A是否离线

// client_id http请求client_id
// uid http请求uid
Gateway::bindUid($client_id, $uid);

// A为车场客户端编号
$client_ids = Gateway::getClientIdByUid('A');
$status = Gateway::isUidOnline('A');

if (!$status || !$client_ids) {
    Gateway::sendToUid(http请求client_id, json_encode(['code' => 0, 'message' => '车场客户端已离线']));
    return;
}

// 向客户端A发送请求
Gateway::sendToUid('A', json_encode($message));

先检测客户端A状态。但是这种方法建立在client_id触发了onClose回调,像断网这种情况,客户端是没办法触发onClose回调

2、服务端向客户端发送心跳包检测客户端状态

我看官方文档可以通过服务端向客户端发送心跳包检测客户端状态,假设我设置心跳包3s/次,但是这种也会存在心跳包刚检测客户端正常,过了1s客户端因为断网离线了,这时候有http请求进来,服务端还不知道客户端连接不上了,还是会出现上面我所说的情况

你期待的结果是什么?实际看到的错误信息又是什么?

请问大家有合适的解决方案吗?

阅读 862
1 个回答

金额为什么需要放在客户端,为什么不能直接记录在服务端?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题