网络编程释疑之:TCP半开链接的处理

熟悉基于TCP协议进行linux高性能、高并发服务端编程的朋友确定应该知道每一个文件描述符及其所占的资源对并发量的影响。在这种7*24甚至*365不间断运行的服务器上,一个描述符被浪费,两个被浪费...若是被浪费的多了,那还何谈高并发,高性能。除去文件描述被正常占用的状况外,是什么致使了咱们可用的文件描述符愈来愈少呢?linux

什么是半开链接?编程

当客户端与服务器创建起正常的TCP链接后,若是客户主机掉线(网线断开)、电源掉电、或系统崩溃,服务器进程将永远不会知道(经过咱们经常使用的select,epoll监测不到断开或错误事件),若是不主动处理或重启系统的话对于服务端来讲会一直维持着这个链接,任凭服务端进程如何望穿秋水,也永远再等不到客户端的任何回应。这种状况就是半开链接,浪费了服务器端可用的文件描述符。服务器

如何处理?网络

熟悉套接字通用选项的朋友必定已经有了想法。TCP套接字不是有个保持存活选项SO_KEEPALIVE嘛,若是在两个小时以内在该套接字的任何一个方向上都没数据交换,TCP就自动给对端发送一个保持存活探测分节,若是此TCP探测分节的响应为RST,说明对端已经崩溃且已经从新启动,该套接字的待处理错误被置为ECONNRESET,套接字自己则被关闭。若是没有对此TCP探测分节的任何响应,该套接字的处理错误就被置为ETIMEOUT,套接字自己则被关闭。多线程

确实,这个选项确实能够处理咱们前面遇到的TCP半开链接的问题,可是默认两小时间隔探测的实时性是否是差了些呢?固然,咱们能够经过修改内核参数改小时间间隔,完美了吧?可是必须注意的是大多数内核是基于整个内核维护这些时间参数的,而不是基于每一个套接字维护的,所以若是把无活动周期从两小时改成(好比)2分钟,那将影响到该主机上全部开启了此选项的套接字。我想你们都不会愿意承担服务器端的这种不肯定性吧。另外,心跳除了说明应用程序还活着(进程存在,网络畅通),更重要的是代表应用程序能正常工做。而SO_KEEPALIVE由操做系统负责探查,即使是进程死锁或有其余异常,操做系统也会正常收发TCP keepalive消息,而对方没法得知这一异常。并发

不要紧,其实咱们能够在应用层模拟SO_KEEPALIVE的方式,用心跳包来模拟保活探测分节。因为服务器一般要承担成千上万的并发链接,因此确定是由客户端在应用层进行心跳来模拟保活探测分节,客户端屡次收不到服务器的响应时可终止此TCP链接,而服务端可监测客户端的心跳包,若在必定时间间隔内未收到任何来自客户端的心跳包则能够终止此TCP链接,这样就有效避免了TCP半开链接的状况。ide


参考书籍:高并发

《UNIX网络编程:卷1》性能

《Linux多线程服务端编程》操作系统

相关文章
相关标签/搜索