TCP连接的建立和关闭
传输层的协议有两个,TCP协议和UDP协议。TCP协议是TCP/IP协议族中一个重要的协议,相对于UDP协议,TCP协议的特点是:面向连接、字节流和可靠传输。
使用TCP协议通信的双方必须先建立连接,才能开始数据的读写,而数据交换完成后,通信双方都必须断开连接以释放系统资源。在TCP连接从建立到断开的整个过程中,连接两端的状态机会经历不同的状态变迁。
TCP连接的建立与关闭:

第1个TCP报文段包含SYN标志,是一个同步报文段,即客户端向服务端发送连接请求。同时该报文段包含一个ISN值为x的序号。第2个TCP报文段也是个同步报文段,表示服务端同意与客户端建立连接,同时发送自己的ISN值为y的序号,并对第一个同步报文段进行确认(ACK)。确认值为x+1,即第一个同步报文段的序列号+1。第3个报文段是客户端对第二个报文段的确认,确认值为y+1。至此,TCP的连接就建立起来了。建立TCP连接的三个步骤被称为TCP的三次握手。
后面四个报文段是关闭连接的过程,第4个TCP报文段包含FIN标志,这是一个结束报文段,即客户端请求关闭连接。服务端用TCP报文段5来确认该结束报文段。紧接着服务端发送自己的结束报文段6,客户端则用TCP报文段7给予确认。在关闭连接过程中,因为客户端先发送结束报文段,称客户端执行主动关闭,而服务端执行被动关闭。
注:
ACK标志:表示确认号是否有效,称携带ACK标志的数据报文段称为确认报文段。
SYN标志:表示请求建立一个连接,称携带SYN标志的数据报文段称为同步报文段。
FIN标志:表示通知对方本端要关闭连接,称携带FIN标志的数据报文段为结束报文段。
TCP的半关闭:
TCP连接是全双工的,它允许两个方向的数据传输被独立关闭。即通信的一方可以发送结束报文段给对方,告诉它本端已经完成了数据的发送,但允许接受来自对方的数据,直到对方也发送结束报文段关闭连接。TCP连接的这种状态称为半关闭状态
TCP的状态转移:
TCP连接的任意一端在任意时刻都处于某种状态。linux系统中服务器通过listen系统调用进入LISTEN状态,被动等待客户端连接,此时执行的是被动打开。服务端一旦监听到某个连接请求(收到同步报文段),就将该连接放入内核的等待队列中,并向客户端发送带SYN标志的确认报文段。此时该连接处于SYN_RCVD态,SYN_RCVD是TCP三次握手的中间状态。如果服务器成功接收到客户端发送回的确认报文段,则该连接转移到ESTABLISHED状态。ESTABLISHED状态是连接双方都能进行双向数据传输的状态。
当客户端主动关闭连接时(客户端向服务器发送FIN结束报文段),同时连接进入FIN_WAIT_1状态。服务端通过返回确认的报文段使连接进入CLOSE_WAIT状态,这个状态意义很明确:等待服务器应用程序关闭连接。此时,客户端接收到服务端的确认报文,则连接转为FIN_WAIT_2状态。当客户端处于FIN_WAIT_2状态而服务端处于CLOSE_WAIT状态时,这一对状态是可能发生半关闭的状态。若此时服务器检测到客户端关闭连接后立刻发送一个结束报文段来关闭连接,则客户端将给予确认并进入TIME_WAIT状态,同时服务端连接状态转移到了LAST_ACK状态,以等待客户端对结束报文段的的最后一次确认,一旦确认完成,连接就彻底关闭了。

TIME_WAIT状态:
客户端在接受到服务器的结束报文(TCP报文段6)后,并没有直接进入CLOSED状态,而是转移到TIME_WAIT状态。在这个状态,客户端要等待一段长为2MSL(Maximum Segment Life 报文段最大生存时间)的时间,才能完全关闭
TIME_WAIT状态存在的原因有两点:
1、可靠地终止TCP连接
2、保证让迟到的报文段有足够时间被识别并处理
在linux系统上,一个TCP端口不能被打开多次。当一个TCP连接处于TIME_WAIT状态时,我们将无法立刻使用该连接占用的端口来建立一个新连接。如果不存在TIME-WAIT状态,则应用程序能立刻建立一个和刚关闭的连接相似的连接(具有相同的IP地址和端口号)。这个新的、和原来相似的连接被人称为原来连接的化身,新的化身可能接受到属于原来连接的、携带应用程序数据的TCP报文段,这是不希望发生的,也是TIME_WAIT状态存在的一个原因。
另外因为TCP报文段的最大生存时间为MSL,所以坚持2MSL时间的TIME_WAIT状态能够确保网络上两个传输方向上尚未被接收到的、迟到的TCP报文段都已被丢弃,这样一个连接的新的化身可以在2MSL时间后安全的建立,而绝对不会接收到属于原来连接的的应用程序数据,这就是TIME_WAIT状态要持续2MSL时间的原因
本文部分内容参考《linux高性能服务器编程》,作者游双
浙公网安备 33010602011771号