Looyao's Blog

记录一些点滴

SOCKET:探测客户端连接是否断开

| Comments

上一篇介绍了使用nginx扩展来实现websocket服务,最近自己使用C++造了同样的轮子(comet),但是性能比nginx扩展要好些。思路是发布消息使用HTTP,订阅走websocket,只实现了websocket的推送消息。使用epoll/kqueue + 多线程,超时检测单独开一个线程定期扫描。但是最近把检查客户端是否在线的逻辑集成进来,一般情况,客户端主动close服务端是可以马上获知状态,但是如果客户端突然断电、拔掉网线,这种情况,是没法及时获知的,只能依赖那个超时检查线程遍历,但是这并不很及时。然后继续查找一些简单的解决方案。

最初准备调整系统TCP keepalive参数,主要有三个:

1
2
3
4
5
6
7
8
# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200

# cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75

# cat /proc/sys/net/ipv4/tcp_keepalive_probes
9

第一个参数的单位是秒,默认值是两小时,意思是两小时后开始检测对端状态。第二个参数是检查的间隔,第三个是尝试次数,如果在尝试次数内都没有对端的ACK响应,就标记为连接断开。可以把参数值设置的小一些来解决上边的问题。但还有另外一种情况就是客户端异常了,TCP连接在,但是客户端卡死(代码bug,死锁之类),这种通过TCP keepalive是无法检测的。PS:参数调整不一定要修改全局配置,可以在应用逻辑代码里边使用setsockopt来设置。

接下来的方案就是要实现心跳机制了,websocket协议自带PING/PONG,实现起来也不算麻烦,方案就是客户端定时发送PING,服务端收到响应一个PONG,并更新alive时间,这里没有选择在服务端实现PING。这样客户端的在线状态就相对准确的判断了。

小记一下。

参考资料:

1、https://tools.ietf.org/html/rfc6455#section-5.5.2

2、http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/usingkeepalive.html

Comments