配色: 字号:
TCP断开
2013-07-13 | 阅:  转:  |  分享 
  


Tcp断开连接

Postedon2010-08-1115:34kongkongzi阅读(1179)评论(0)编辑收藏引用所属分类:networkprogramming

TCP状态转移要点

TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源。在众多TCP状态中,最值得注意的状态有两个:CLOSE_WAIT和TIME_WAIT。

1、LISTENING状态

FTP服务启动后首先处于侦听(LISTENING)状态。

2、ESTABLISHED状态

ESTABLISHED的意思是建立连接。表示两台机器正在通信。

3、CLOSE_WAIT

对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT此时我方要调用close()来使得连接正确关闭

4、TIME_WAIT

我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT。TCP协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT状态的连接占用的资源不会被内核释放,所以作为服务器,在可能的情况下,尽量不要主动断开连接,以减少TIME_WAIT状态造成的资源浪费。

目前有一种避免TIME_WAIT资源浪费的方法,就是关闭socket的LINGER选项。但这种做法是TCP协议不推荐使用的,在某些情况下这个操作可能会带来错误。







在连接撤销过程中,有如下四个过程:



1.HOST1上的应用程序关闭己方的连接导致TCP发送一个FIN消息给HOST2。

2.HOST2发送一个确认消息给HOST1,并且HOST2把FIN作为EOF递交给HOST2上的应用程序。

3.一段时间过后,HOST2上的应用程序关闭它那边的连接,引发一个FIN消息给HOST1。

4.HOST1给HOST2发送一个确认消息,然后HOST2关闭连接并释放资源,然而,HOST1却没有关闭连接,而是进入了TIME_WAIT状态,并为两个最大段生存时间(2MSL)保留在此状态.



为什么需要time_wait?

1.因为在第四步的时候,HOST1发送的ACK可能丢失并导致HOST2重新发送FIN消息,TIME_WAIT维护连接状态.

如果执行主动关闭的一方HOST1不进入到TIME_WAIT状态就关闭连接那会发生什么呢?当重传的FIN消息到达时,因为TCP已经不再有连接的信息了,所以就用RST(重新启动)消息应答,导致HOST2进入错误的状态而不是有序终止状态,如果发送最后ACK消息的一方处于TIME_WAIT状态并仍然记录着连接的信息,它就可以正确的响应对等方HOST2的FIN消息了.

2.TIME_WAIT为连接中”离群的段”提供从网络中消失的时间.

考虑一下,如果延迟或者重传段在连接关闭后到达时会发生什么呢?通常情况下,因为TCP仅仅丢弃该数据并响应RST消息,所以这不会造成任何问题。当RST消息到达发出延时段的主机时,因为该主机也没有记录连接的任何信息,所以它也丢弃该段。然而,如果两个相同主机之间又建立了一个具有相同端口号的新连接,那么离群的段就可能被看成是新连接的,如果离群的段中数据的任何序列号恰恰在新连接的当前接收窗口中,数据就会被重新接收,其结果就是破坏新连接。











一、TCP连接关闭的几种方式:

1、“正常”关闭:调用close()关闭socket、没close但进程正常结束(当然这是不应该的做法)、进程core掉、在shell命令行中kill掉进程,都可抽象成“正常”关闭。因为即使core掉,内核也会马上帮应用程序回收(close)socket文件描述符。

“正常”关闭,默认情况下(非默认即设置Linger下面会介绍),关闭端即客户端TCP层会发FIN包,对端即服务器TCP层收到后,回ACK,客户端进入FIN_WAIT2状态。此时,TCP终止连接的4个分组中服务器应该发的第3个分组FIN包,其TCP层是不会主动发的,只有服务器端socket“正常”关闭,才会发出这个FIN包。至此,客户端进入TIME_WAIT状态。

2、“非”正常关闭:客户端崩溃了,此时肯定发不出FIN包了(当然啦,内核都没机会帮应用程序回收资源了)。这种情况,服务器端有如下两种情况:

A、服务器send数据,因为客户端已经崩溃,服务器收不到ACK自然会不停的重传。源自

Berkeley的重传机制,重传8次,相对第一次传的15分钟后仍没收到ACK,则返回

ETIMEDOUT或EHOSTUNREAC错误。如果服务器不理会这个错误,再次调用send,则

立马返回BrokenPipe错误。

注:15分钟超时可以在/proc/sys/net/ipv4/tcp_retries2中修改

B、服务器不发任何数据了,那只有靠应用层心跳检测机制或Keepalive,来发觉TCP断连了。

二、SO_LINGER套接口选项

A、l_onoff设置为0,这也是默认情况,函数close()是立即返回的,然后TCP连接双方是通过

FIN、ACK4分组来终止TCP连接的。当然,发送缓冲区还有数据的话,系统将试着将这些数据

发送到对方。

B、l_onoff非0,l_linger设置0,函数close()立即返回,并发送RST终止连接,发送缓冲区的数据丢弃。

C、l_onoff非0,l_linger非0,函数close()不立即返回,而是在(a)发送缓冲区数据发送完并得到确认

(b)l_linger延迟时间到,l_linger时间单位为微妙。两者之一成立时返回。如果在发送缓冲区数据发送

完并被确认前延迟时间到的话,close返回EWOULDBLOCK(或EAGAIN)错误。

三、客户端TCP连接“正常”关闭,服务器的几种情况:

情形客户端l_onoff设置为0,

“正常”关闭客户端l_onoff非0,l_linger设置0,“正常”关闭

服务器阻塞模式send,正阻塞在send函数未返回客户端TCP发送FIN,服务器send函数返回成功(返回字节数是实际拷贝到发送缓冲区的字节数)。客户端发送RST。如果服务器再次调用send,将返回errno[32]:Brokenpipe客户端TCP发送RST,服务器函数返回成功(返回字节数是实际拷贝到发送缓冲区的字节数)。若服务器再次调用send,则返回-1,errno[104]:Connectionresetbypeer。若再次调用send,则返回-1,errno[32]:Brokenpipe

服务器空闲客户端TCP发送FIN,若服务器没理会而调用send,客户端发送RST,send返回-1,errno[32]:Brokenpipe客户端TCP发送RST,若服务器没理会而调用send,send返回-1,errno[104]:Connectionresetbypeer。若再次调用send,则返回-1,errno[32]:Brokenpipe

总之,1、收到对端RST后,仍然调入send(),则返回Connectionresetbypeer,再次调用send(),则返回Brokenpipe

2、收到对端FIN后,仍然调研哪个send(),直接返回Brokenpipe

献花(0)
+1
(本文系搁***浅首藏)