关于TCP/IOCP构架中出现的Socket假死连接解决方案
如果在2台不同的公网机器,对TCP的c/s做过详细的压力测试,那么很不幸,会有很多人发现自己的server端会出现大量的假死连接。
假死连接具体表现如下:
1、在s端机器上,会有一些处于TCP_ESTABLISHED状态的“正常”连接;
2、但是在c端机器上,你的tcp客户端已经提示当前连接已经断开,比如10053/10054。
3、c端此时虽然可以断线重连s端,但是上一次的连接状态依然被s认为有效,并且得不到正确释放(例如IOCP构架中的套接字上下文及接收/发送缓冲区)。
这种情况虽然不常见,但是确实是存在的,具体造成的原因可以参考tcp/ip断开连接fin过程,如果你认为这种事情发生概率微不足道,不做任何处理的话,你的s长时间运行后,会面临大量假死连接得不到正常释放,然后服务器越来越慢,IO处理效率越来越低。
最常见诡异现象:采用IOCP的c/s构架中,明明c端closesocket了,但是s端的GCQS就是不会返回失败信息!
网上通常的解决方案:
1、对连接上的套接字做保活处理,即设置keeplive,此后如果在规定时间内无数据传输,那么tcp协议栈会自动发送keeplive探测包,以维护当前连接有效性。如果你在s端采用这个方案,那么很可惜,假死连接不会得到根本性的解决。常见现象:c端意外断电、网络异常终止、被第三方软件或防火墙干掉等。
2、c端定时发送用户层心跳包,s端针对每个已连接套接字记录最后一次收到心跳包的时间,同时开启线程定时检测:超过XX秒还未收到心跳包的套接字,kill掉,释放占用的上下文及收发缓冲区资源。
稳定的c/s构架可能不会用协议栈的keeplive(没办法100%干掉假死连接),但是一定会做用户层的心跳检测机制。