TCP连接拔掉网线后会发生什么

作者: veaxen 分类: 网络 发布时间: 2017-09-22 16:18

什么是半开连接?

接触过TCP/IP协议的应该都能理解三次握手之后客户端和服务端就都认为连接已经建立,这其实就是一个我们双方认为的连接建立好了的过程,是一种虚拟的连接,如果三次握手后,我们拔掉网线?(WTF)那对于服务端和客户端都是不知道的,他们都以为连接建立着呢。这时候就有很多问题了,一般来说都是服务端的问题比较大,举个粒子,如果服务器不对这种情况进行处理,那就会一直占用服务器的资源(比如说服务器的文件描述符,一个连接至少占用一个文件描述符),当数量多到一定情况时,服务器就会宕掉。

对于类似的情况,我们称之为半开连接,我们如何处理这种半开连接呢?

怎么处理?

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

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

没关系,其实我们可以在应用层模拟SO_KEEPALIVE的方式,用心跳包来模拟保活探测分节。由于服务器通常要承担成千上万的并发连接,所以肯定是由客户端在应用层进行心跳来模拟保活探测分节,客户端多次收不到服务器的响应时可终止此TCP连接,而服务端可监测客户端的心跳包,若在一定时间间隔内未收到任何来自客户端的心跳包则可以终止此TCP连接,这样就有效避免了TCP半开连接的情况。

参考书籍:
《UNIX网络编程:卷1》
《Linux多线程服务端编程》

转载自:http://yaocoder.blog.51cto.com/2668309/1309358

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注