读《TCP/IP详解》第17、18章:TCP传输控制协议的连接和终止

时间:2022-12-20 10:20:43

在日常的使用中,TCP和UDP是最频繁的,而其中又以TCP包含的内容更多,更复杂。本书后面几章就专门为我们讲解了TCP协议,包括连接的建立和终止,数据的传送,重传,保活等等。

首先,TCP提供一种面向连接的、可靠的字节流服务,该段话的说明如下:
1. 面向连接意味着两个使用TCP的应用,在交换数据之前必须建立一个TCP连接,而UDP则是不需要连接直接发送数据。
2. 在一个TCP连接中,仅有两方彼此通信,所以广播和多播无法用于TCP
3. TCP通过以下方式来提供可靠性

  • 数据被分割成TCP认为最合适发送的数据块进行传送
  • 当TCP发出一个段后,启动一个定时器,等待目的端确认收到该报文,如果不能及时收到确认,TCP将重新发送这个报文段(TCP的重传机制)
  • 当TCP收到数据时,它将发送一个确认(ACK)。不过该确认不是立即发送,通常将推迟几分之一秒
  • TCP保持首部和数据的校验和,如果收到的段的检验和有错,则TCP将丢弃这个报文段,并不发送确认,以使对端重传数据
  • 在必要情况下,TCP将会对收到的报文段进行重新排序,将收到的数据正确的传给应用层
  • TCP接收端会丢弃重复的数据报
  • TCP提供流量控制,防止较快主机致使较慢主机的缓冲区溢出

    TCP对字节流的内容不做任何解释,所以TCP不知道对端传送的是二进制数据,还是字符流或其他数据。

TCP首部
TCP数据的首部如下图所示:
读《TCP/IP详解》第17、18章:TCP传输控制协议的连接和终止

  1. 每个TCP段都包含一个源端和目的端的端口号,用于寻找各对端的进程,而IP地址,则位于封闭TCP数据的IP报头中。
  2. 一个IP地址和一个端口号也称为一个socket,socket对(包含两端IP地址和端口号)可唯一确定网络中每个TCP连接的双方
  3. 序号用来标识从TCP发送端向TCP接收端发送的数据字节流,表示在这个报文段中的第一个数据字节。

TCP为应用层提供全双工服务。即数据能在两个方向上独立地进行传输,因此,连接的每一端都必须保持每个方向上的传输数据序号

MSS:最长报文大小,每个连接方通常都在通信的第一个报文段中指明该选项,表示本端能接收的最大长度。


TCP的三次握手:

  1. 请求端(主动连接)发送一个SYN段指明打算连接的服务器端口,以及初始序号(ISN),该SYN段为报文段1
  2. 服务端(被动连接)发回包含服务器的初始序号的SYN报文段作为应答,同时将确认序号设置为请求端的ISN+1,以对请求端进行确认,该SYN段为报文段2
  3. 请求端必须将确认序号设置为服务端的ISN+1,以对服务端的SYN进行确认,该段为报文段3

TCP的四次挥手:

由于TCP是全双工方式,因此必须在每个方向上单独的进行关闭,所以关闭TCP连接需要四次挥手:

  1. 发送端(A端)发送一个FIN给对端(B端),表示要终止当前方向的数据传输
  2. B端发送FIN的ACK确认关闭A端到B端的数据传输
  3. B端发送一个FIN给A端,表示要终止当前方向的数据传输
  4. A端发送ACK确认关闭B端到A端的数据传输,TCP连接正常断开

过程如下图所示(图片引用自TCP连接与终止):
读《TCP/IP详解》第17、18章:TCP传输控制协议的连接和终止

通常来说,连接都是由客户端发起(调用connect函数),每一端都能主动关闭连接(调用close函数),不过一般也是由客户端决定何时终止TCP连接。

当一个连接被建立时,每一方都有用于通告它期望接收的MSS选项(只能出现在SYN报文段中),如果一方不接收来自另一方的MSS值,则MSS默认定为536字节。

连接的一端在结束它的发送后还能接收来自另一端数据的能力,这就是所谓的半关闭,即只关闭一个方向上的数据流向,如图所示:
读《TCP/IP详解》第17、18章:TCP传输控制协议的连接和终止
如上图所示,客户在关闭数据发送的通道时,依然可以接收来自另一端的数据,直到对端发送FIN终止符关闭通道为止。

TCP状态变迁图
TCP连接与终止的状态变迁,如变迁图所示:
读《TCP/IP详解》第17、18章:TCP传输控制协议的连接和终止

先看粗实线部分:
1. 客户端最先处于CLOSED状态,然后调用connect,发送SYN,主动打开连接,进入SYN_SEND状态
2. 收到服务端发送过来的SYN,ACK,并确认服务端的SYN之后,进入到ESTABLISHED状态,即连接已经建立
3. 客户端调用close函数,发送一个FIN,进入到FIN_WAIT_1状态
4. 服务端确认FIN,回传ACK,客户端进入FIN_WAIT_2状态
5. 服务端发送FIN,客户端确认FIN并发送ACK确认,进入到TIME_WAIT状态,双方连接关闭。等待2MSL超时,回到CLOSED状态

再看虚线部分:
1. 服务端最先处于CLOSED状态,然后调用listen函数,进入到LISTEN监听状态
2. 收到来自客户端的SYN,服务端发回ACK确认,并发送SYN给客户端,进入到SYN_RCVD状态
3. 客户端发送ACK确认,服务端进入到ESTABLISHED状态,即连接已建立
4. 服务端收到客户端的FIN,并回传ACK确认,进入到CLOSE_WAIT状态
5. 服务端发送FIN,要求关闭连接,进入到LAST_ACK状态
6. 服务端收到客户端的ACK确认,服务端回到CLOSED状态

最后看细实线部分:
细实线部分代表了两种特殊情况,即同时打开和同时关闭,如果两端同时打开一个连接,在这种情况下,需要通过四次握手才能建立,如下图所示:
读《TCP/IP详解》第17、18章:TCP传输控制协议的连接和终止

同时打开

  1. 两者主动打开,都发送SYN给对端,两者都进入到SYN_SENT状态
  2. 两者收到对端的SYN,进入到SYN_RCVD状态
  3. 两者各自发送对端的ACK确认和SYN报文段,建立连接。

同时关闭

读《TCP/IP详解》第17、18章:TCP传输控制协议的连接和终止

  1. 当应用层调用close时,两端均从ESTABLISHED状态进入到FIN_WAIT_1状态,从而两端各自发送一个FIN
  2. 收到FIN后,两者均进入到CLOSING状态,并发送ACK确认对端的FIN
  3. 收到来自对端的ACK确认之后,状态变化为TIME_WAIT,待超时后中断连接,进入到CLOSED状态

TIME_WAIT(2MSL)等待状态:
每个具体TCP实现必须选择一个报文段最大生存时间MSL,它是任何报文被丢弃前在网络内的最长时间。当TCP执行主动关闭,并发回最后的一个ACK,该连接必须在TIME_WAIT状态停留2MLSL的时间,这样可让TCP再次发送最后的ACK以防其丢失。

平静时间:指TCP在重新启动后的MSL秒内不能再建立任何连接

连接请求队列:
在伯克利的TCP实现中,采用以下规则来处理多个连接请求到达时,而服务器处于忙碌状态时的问题:
1. 正等待连接请求的一端(服务端)有一个固定长度的连接队列,该队列中的连接已被TCP接受,但还没有被应用层接受
2. 应用层指明该队列的最大长度,通常称为积压值(backlog),取值范围是0~5之间,通常通过调用listen函数来设置backlog值
3. 当一个连接请求到达时,TCP使用一个算法,根据当前连接队列中的连接数来确定是否接收这个连接
4. 对于新的连接请求,该TCP监听的端点连接队列中还有空间,TCP模块将对SYN进行确认并完成连接
5. 对于新的连接请求,如果连接队列中已没有空间,TCP将不会受理这些收到的SYN,也并不回传任何报文段

TCP报头的定义:
读《TCP/IP详解》第17、18章:TCP传输控制协议的连接和终止