TCP协议

来源:互联网 发布:红外循迹小车pid算法 编辑:程序博客网 时间:2024/05/22 07:05


TCP连接是全双工的,所以它允许两个方向的数据传输被独立关闭。换言之,通信的一端可以发送结束报文段给对方,告诉它本端已经完成了数据的发送,但允许继续接收来自对方的数据,直到对方也发送结束报文段以关闭连接。TCP连接的这种状态称为半关闭(half close)状态

服务器和客户端应用程序判断对方是否已经关闭连接的方法是:read系统调用返回0(收到结束报文段)。当然,Linux还提供其他检测连接是否被对方关闭的方法.
socket网络编程接口通过shutdown函数提供了对半关闭的支持, 但是使用半关闭的应用程序很少见。


TCP状态转移

TCP连接的任意一端在任一时刻都处于某种状态,当前状态可以通过netstat命令查看。
TCP连接从建立到关闭的整个过程中通信两端状态的变化。

粗虚线表示典型的服务器端连接的状态转移;粗实线表示典型的客户端连接的状态转移。CLOSED是一个假想的起始点,并不是一个实际的状态。


服务器通过listen系统调用进入LISTEN状态,被动等待客户端连接,因此执行的是所谓的被动打开。
服务器一旦监听到某个连接请求(收到同步报文段),就将该连接放入内核等待队列中,并向客户端发送带SYN标志的确认报文段。此时该连接处于SYN_RCVD状态。
如果服务器成功地接收到客户端发送回的确认报文段,则该连接转移到ESTABLISHED状态。ESTABLISHED状态是连接双方能够进行双向数据传输的状态。

当客户端主动关闭连接时(通过close或shutdown系统调用向服务器发送结束报文段),服务器通过返回确认报文段使连接进入CLOSE_WAIT状态。这个状态的含义很明确:等待服务器应用程序关闭连接。
通常,服务器检测到客户端关闭连接后,也会立即给客户端发送一个结束报文段来关闭连接。这将使连接转移到LAST_ACK状态,以等待客户端对结束报文段的最后一次确认。一旦确认完成,连接就彻底关闭了。

下面讨论客户端的典型状态转移过程,此时我们说的连接状态都是指该连接的客户端的状态。

客户端通过connect系统调用主动与服务器建立连接。connect系统调用首先给服务器发送一个同步报文段,使客户端连接转移到SYN_SENT状态。此后,connect系统调用可能因为如下两个原因失败返回:
如果connect连接的目标端口不存在(未被任何进程监听),或者该端口仍被处于TIME_WAIT状态的连接所占用(见后文),则服务器将给客户端发送一个复位报文段,connect调用失败。
如果目标端口存在,但connect在超时时间内未收到服务器的确认报文段,则connect调用失败。
connect调用失败将使客户端连接立即返回到初始的CLOSED状态。如果客户端成功收到服务器的同步报文段和确认,则connect调用成功返回,客户端连接转移至ESTABLISHED状态。

当客户端执行主动关闭时,它将向服务器发送一个结束报文段,同时客户端连接进入FIN_WAIT_1状态。
若此时客户端收到服务器专门用于确认目的的确认报文段 ,则客户端连接转移至FIN_WAIT_2状态。
当客户端处于FIN_WAIT_2状态时,服务器处于CLOSE_WAIT状态,这一对状态是可能发生半关闭的状态。此时如果服务器也关闭连接(发送结束报文段),则客户端将给予确认并进入TIME_WAIT状态。
图3-8还给出了客户端从FIN_WAIT_1状态直接进入TIME_WAIT状态的一条线路(不经过FIN_WAIT_2状态),前提是处于FIN_WAIT_1状态的服务器直接收到带确认信息的结束报文段(而不是先收到确认报文段,再收到结束报文段)。

前面说过,处于FIN_WAIT_2状态的客户端需要等待服务器发送结束报文段,才能转移至TIME_WAIT状态,否则它将一直停留在这个状态。
如果不是为了在半关闭状态下继续接收数据,连接长时间地停留在FIN_WAIT_2状态并无益处。连接停留在FIN_WAIT_2状态的情况可能发生在:客户端执行半关闭后,未等服务器关闭连接就强行退出了。
此时客户端连接由内核来接管,可称之为孤儿连接(和孤儿进程类似)。
Linux为了防止孤儿连接长时间存留在内核中,定义了两个内核变量:/proc/sys/net/ipv4/tcp_max_orphans和/proc/sys/net/ipv4/tcp_fin_timeout。前者指定内核能接管的孤儿连接数目,后者指定孤儿连接在内核中生存的时间。
至此,我们简单地讨论了服务器和客户端程序的典型TCP状态转移路线。


TIME_WAIT状态
客户端连接在收到服务器的结束报文段之后,并没有直接进入CLOSED状态,而是转移到TIME_WAIT状态。
在这个状态,客户端连接要等待一段长为2MSL(Maximum Segment Life,报文段最大生存时间)的时间,才能完全关闭。MSL是TCP报文段在网络中的最大生存时间,标准文档RFC 1122的建议值是2?min。
TIME_WAIT状态存在的原因有两点:
可靠地终止TCP连接。
保证让迟来的TCP报文段有足够的时间被识别并丢弃。



0 0