一、TCP长连接
正常情况下,一条TCP连接建立后,只要双不提出关闭请求并且不出现异常情况,这条连接是一直存在的,操作系统不会自动去关闭它,甚至经过物理网络拓扑的改变之后仍然可以使用。所以一条连接保持几天、几个月、几年或者更长时间都有可能,只要不出现异常情况或由用户(应用层)主动关闭。
在编程中,往往需要建立一条TCP连接,并且长时间处于连接状态。所谓的TCP长连接并没有确切的时间限制,而是说这条连接需要的时间比较长。
二、TCP连接的正常中断
TCP连接在事务处理完毕之后,由一方提出关闭连接请求,双方通过四次握手(建立连接是三次握手,当然可以通过优化TCP/IP协议栈来减少握手的次数来提高性能,但这样会形成不规范或者不优雅的通信)来正常关闭连接
三、TCP连接的异常中断
导致TCP连接异常中断的因素有:物理连接被中断、操作系统down机、程序崩溃等等。
四、如何检测TCP连接已经中断
对于实时性要求较高的网络通信程序,往往需要更加及时的获取已经中断的连接,从而进行及时的处理。但如果对方的连接异常中断,往往是不能及时的得到对方连接已经中断的信息,操作系统检测连接是否中断的时间间隔默认是比较长的,即便它能够检测到,但却不符合我们的实时性需求,所以需要我们进行手工去不断探测。
探测的方式有两种:
1、改变socket的keepalive选项,以使socket检测连接是否中断的时间间隔更小,以满足我们的及时性需求。有关的几个选项使用和解析如下:
A、我们在检测对端以一种非优雅的方式断开连接的时候,可以设置SO_KEEPALIVE属性使得我们在2小时以后发现对方的TCP连接是否依然存在。用法如下:
keepAlive = 1;
setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
B、如果我们不想使用这么长的等待时间,可以修改内核关于网络方面的配置参数,也可设置SOCKET的TCP层(SOL_TCP)选项TCP_KEEPIDLE、TCP_KEEPINTVL和TCP_KEEPCNT。
TCP_KEEPIDLE:开始首次KeepAlive探测前的TCP空闭时间
The tcp_keepidle parameter specifies the interval of inactivity that causes TCP to generate a KEEPALIVE transmission for an application that requests them. tcp_keepidle defaults to 14400 (two hours).
TCP_KEEPINTVL:两次KeepAlive探测间的时间间隔
The tcp_keepintvl parameter specifies the interval between the nine retries that are attempted if a KEEPALIVE transmission is not acknowledged. tcp_keepintvl defaults to 150 (75 seconds).
TCP_KEEPCNT:断开前的KeepAlive探测次数
The TCP_KEEPCNT option specifies the maximum number of keepalive probes to be sent. The value of TCP_KEEPCNT is an integer value between 1 and n, where n is the value of the systemwide tcp_keepcnt parameter.
如果心搏函数要维护客户端的存活,即服务器必须每隔一段时间必须向客户段发送一定的数据,那么使用SO_KEEPALIVE是有很大的不足的。因为SO_KEEPALIVE选项指"此套接口的任一方向都没有数据交换"。在Linux 2.6系列上,上面话的理解是只要打开SO_KEEPALIVE选项的套接口端检测到数据发送或者数据接受就认为是数据交换。因此在这种情况下使用 SO_KEEPALIVE选项 检测对方是否非正常连接是完全没有作用的,在每隔一段时间发包的情况, keep-alive的包是不可能被发送的。上层程序在非正常断开的情况下是可以正常发送包到缓冲区的。非正常端开的情况是指服务器没有收到"FIN" 或者"RST"包。
2、在应用层使用heartbeat来主动检测。