传输层协议TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,会对数据的传输进行一个详细的控制。
TCP协议段格式
TCP协议段格式是TCP协议在网络传输数据时所使用的结构单元:
源端口(Source Port)
- 大小:2字节
- 描述:发送端(TCP客户端)的应用程序端口号,用于标识发送数据的应用程序。通过源端口和源IP地址,可以确定发送端的唯一地址。
目的端口(Destination Port)
- 大小:2字节
- 描述:接收端(TCP服务器)的应用程序端口号,用于标识接收数据的应用程序。与目的IP地址一起,可以确定接收端的唯一地址。
序号(Sequence Number)
- 大小:4字节
- 描述:用于标识TCP传输中每个字节的序号。TCP是面向字节流的协议,因此为每个字节分配一个序号,以确保数据的顺序和完整性。序号是报文段中第一个数据字节的序号。
确认号(Acknowledgment Number)
- 大小:4字节
- 描述:期望从对方接收的下一个字节的序号。它告诉对方,本报文段发送方的数据已经成功接收到了哪一个序号。只有当ACK标志位为1时,确认号才有效。
数据偏移/首部长度(Data Offset/Header Length)
- 大小:4字节(但其中只有4位用于表示首部长度)
- 描述:表示TCP报文段的首部长度,以32位(即4字节)为单位。由于TCP报文段的首部可能包含可选项,因此其长度是不固定的。这个字段实际上是一个4位的二进制数,表示首部长度中有多少个32位字(即多少个4字节),因此其取值范围是0-15,对应的首部长度范围是20-60字节。
保留字段(Reserved)
- 大小:通常忽略,因为TCP协议规范中没有明确定义其用途。
标志位(Flags)
- 大小:6位
- 描述:用于控制TCP连接的建立和终止,以及数据的传输方式。主要包括以下几个标志位:
URG(紧急指针有效)
ACK(确认号有效)
PSH(提示接收方立即将数据提交给应用层)
RST(重置连接)
SYN(同步序列号,用于建立连接)
FIN(终止连接)
窗口大小(Window Size)
- 大小:2字节
- 描述:用于流量控制,表示接收方还能够接收的字节数。它告诉发送方在不等待确认应答的情况下,可以继续发送数据的量。
校验和(Checksum)
- 大小:2字节
- 描述:用于校验TCP报文段的首部和数据部分。发送方在发送前计算校验和,接收方在接收后进行校验。如果校验和不匹配,则数据可能已损坏,接收方将丢弃该报文段。
紧急指针(Urgent Pointer)
- 大小:2字节
- 描述:当URG标志位为1时,紧急指针指向紧急数据的最后一个字节的偏移量。紧急数据不需要按照顺序接收,而是可以被接收方优先处理。
选项(Options)
- 大小:长度可变,最大为40字节
- 描述:TCP报文段的可选字段,用于支持额外的功能。例如,最大报文段长度(MSS)、窗口扩大选项、时间戳选项等。
数据部分(Data)
- 大小:长度可变
- 描述:TCP报文段中携带的实际应用层数据。其长度由IP层的数据报长度字段和TCP报文段的首部长度字段共同决定。
ACK应答机制
ACK是一个标志位信号,是一种在计算机网络通信中常用的确认机制,主要用于确保数据的可靠传输,防止数据丢失或重复。
基本原理
- 发送与接收:当一台计算机(或设备)发送数据包或命令给另一台计算机时,它会等待接收方的响应。在等待期间,发送方通常会保留一个新的数据包,直到接收方确认收到之前不会发送下一个数据包。
- 确认回复:一旦接收方成功接收并校验了数据包或命令的完整性和准确性,它会通过回复ACK消息来确认收到。ACK消息通常包含一个标志位,指示接收成功。
- 超时重传:如果发送方在一定时间内没有收到ACK消息,它会假定数据包在传输过程中被丢失或出现问题,并会重新发送该数据包,并继续等待ACK消息,直到接收成功为止。这就是所谓的超时重传机制。
- 序列号管理:为了防止数据重复,发送方会给每个数据包分配一个唯一的序列号。接收方在发送ACK消息时,也会将序列号包含在其中。这样,发送方就可以确保它所发送的数据包接收方只收到一次。
ACK应答机制的作用
- 确保数据可靠性:通过ACK应答机制,发送方可以确保发送的数据包已经成功被接收方接收并校验,从而保证了数据的可靠性。
- 防止数据丢失:如果数据包在传输过程中丢失,发送方可以通过超时重传机制重新发送数据包,确保数据能够到达接收方。
- 防止数据重复:通过序列号管理,接收方可以确保不会重复处理相同的数据包,从而避免了数据的重复。
- 提高通信效率:通过ACK应答机制,发送方可以及时得知数据是否成功到达接收方,避免了数据重传的不必要开销,提高了通信效率。
连接管理机制
三次握手
TCP连接建立时需要客户端与服务端之间通过"三次握手"来确认双方的发送和接收能力正常,从而建立可靠的连接。
- 客户端发送的SYN报文中的序列号(Seq)是客户端的初始序列号(ISN)。
- 客户端发送SYN报文后,进入SYN_SENT状态,表示已发送连接请求,等待服务器应答。
第二次握手:服务器收到客户端的SYN报文后,发送一个SYN+ACK(同步序列号+确认)报文给客户端,以确认客户端的连接请求,并同时发送自己的SYN报文以请求与客户端建立连接。服务器进入SYN_RCVD(同步接收)状态。
- 服务器发送的SYN+ACK报文中的确认号(Ack)是客户端初始序列号加1(Seq+1)。
- 服务器发送的SYN报文中的序列号(Seq)是服务器的初始序列号(ISN)。
第三次握手:客户端收到服务器的SYN+ACK报文后,向服务器发送一个ACK报文,以确认服务器的SYN报文。此时,客户端和服务器都进入ESTABLISHED(已建立连接)状态,表示连接建立成功,可以开始传输数据。
- 客户端发送的ACK报文中的确认号(Ack)是服务器初始序列号加1(Seq+1)
四次挥手
TCP断开连接时需要客户端和服务端之间通过四次挥手来确保双方都能正常释放资源并断开连接。
第二次挥手:服务器收到客户端的FIN报文后,发送一个ACK报文给客户端,以确认收到客户端的关闭请求。此时,客户端进入FIN_WAIT_2状态,服务器进入CLOSE_WAIT状态。
第三次挥手:服务器完成数据的传输后,发送一个FIN报文给客户端,表示服务器也希望关闭连接。服务器进入LAST_ACK状态,等待客户端的应答。
第四次挥手:客户端收到服务器的FIN报文后,发送一个ACK报文给服务器,以确认收到服务器的关闭请求。此时,客户端和服务器都进入CLOSED状态,表示连接已经完全断开。
TIME_WAIT状态
在之前测试中,
TIME_WAIT状态是TCP协议中的一个状态,表示一个连接已经被主动关闭方(通常是客户端)关闭,并且等待一段时间(通常为2倍的MSL,即最大报文段生存时间)以确保网络上没有任何延迟或重复数据包。在这个状态下,连接的端口仍然被保留,并且不能立即重新使用。
TIME_WAIT状态的作用
-
可靠地实现TCP全双工连接的终止:
TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接。TIME_WAIT状态的存在是为了处理四次握手过程中可能出现的报文丢失或延迟情况,确保连接的可靠终止。
例如,如果最后的ACK报文丢失,服务器将重发FIN报文,此时客户端必须处于TIME_WAIT状态以重发ACK报文。
-
确保老的报文段在网络中消失,不会影响新建立的连接:
在TIME_WAIT状态期间,等待的2MSL时间足以保证之前连接的所有报文段(包括延迟或重传的报文)在网络中消失,从而避免对新建立的连接造成干扰。
CLOSE_WAIT状态
在我们之前写过的TCP套接字的服务器中:
滑动窗口
滑动窗口是一种流量控制技术,允许发送方在无需等待每个数据段确认的情况下,持续发送多个数据段,从而提高数据传输效率。它通过动态调整窗口大小来控制数据的发送速率,确保数据传输的高效和可靠。
其作用:
- 流量控制:接收方根据自己的处理能力和缓冲区空间,动态调整窗口大小,从而控制发送方的发送速率,避免数据溢出接收方的缓冲区。
- 拥塞控制:通过滑动窗口机制,TCP可以感知网络的拥塞状况,并据此调整发送窗口的大小,以减少网络拥塞的发生。
窗口结构与操作
TCP滑动窗口分为发送窗口和接收窗口两种。
发送窗口:
- 发送窗口包含四个部分:已发送且已收到ACK确认、已发送但未收到ACK确认、未发送但可以发送、未发送也不可以发送。
- 发送窗口的大小由接收窗口大小和拥塞窗口大小共同决定(即取两者中的较小值)。
- 随着数据的发送和确认,发送窗口会不断向前滑动(扩大)。
接收窗口:
- 接收窗口的大小表示接收方当前可用的缓冲区空间大小。
- 接收窗口的大小会随着接收方处理数据的能力而动态变化。
- 接收方在收到数据后,会向发送方发送ACK确认报文,通知发送方已成功接收的数据范围,并更新接收窗口的大小。
工作原理
-
数据发送:发送方将数据分成多个数据段,按顺序发送到接收方。每个数据段都包含一个序列号,标识数据在发送方发送窗口中的位置。
-
确认应答:接收方使用ACK确认应答报文来通知发送方已成功接收的数据段。ACK报文中的序列号表示接收方期望接收的下一个字节的序列号。
-
窗口滑动:发送方在收到ACK确认后,将发送窗口向前滑动,使其离开已确认的数据。这样,发送方可以继续发送新的数据段,只要它在滑动窗口范围内。
-
窗口调整:接收方根据自己的处理能力和缓冲区空间,动态调整接收窗口的大小,并通过ACK报文将新的窗口大小通知给发送方。发送方则根据接收窗口的大小和拥塞窗口的大小,调整自己的发送窗口大小。
丢包重传
当TCP滑动窗口出现丢包时,TCP会采取一系列策略来进行重传,以确保数据的完整性和可靠性。
超时重传(Timeout Retransmission)
- 原理:TCP发送方在发送数据包后会启动一个定时器(超时定时器),如果在规定的超时时间(RTO,Retransmission Timeout)内没有收到对应的确认(ACK),就会认为数据包丢失,然后重新发送这个数据包。
- RTO设置:RTO的值应该略大于报文往返时间的估计值,并且会根据网络状况动态调整。如果超时重发的数据再次超时,TCP会将下一次的超时时间间隔设为先前值的两倍,以避免在网络状况不佳时频繁发送导致网络拥塞。
快速重传(Fast Retransmission)
- 原理:TCP接收方在收到一个失序的数据包时,会立即发送重复确认(通常是重复发送最后一个正确接收到的数据包的确认号),通知发送方需要重传的数据包。发送方在收到连续三个重复确认时,会立即重传对应的数据包,而不必等待超时。
根据确认序号的特点,当接收方在发送重复确认时,发送方在前两次收到重复确认应答时继续发送后面的数据,直到收到第三次重复确认,发送方再把之前丢包的数据段发送过去,而接收方应答会直接应答到最后一个确认序号(表示之前的数据都已经接收到了)
- 优点:快速重传能够比超时重传更快地检测到丢包并启动重传,从而提高数据传输的效率。
SACK(Selective Acknowledgment)
- 原理:SACK选项允许TCP接收方在确认应答中告知发送方哪些数据已经正确接收,哪些数据尚未接收。这样,发送方就可以只重传那些未接收的数据包,而不是盲目地重传所有可能丢失的数据包。
- 优点:SACK能够进一步提高重传的效率,减少不必要的网络带宽消耗。
延迟应答
延迟应答是指TCP接收端在收到发送端发送的数据后,并不立即返回ACK(应答报文)给发送端,而是等待一段时间(这个时间由程序员或系统参数设定)后再发送ACK。
这样做的目的是为了提高传输效率,因为在这段时间内,接收端的接收缓冲区可能会释放一部分空间,从而使得发送端在收到ACK后能够发送更多的数据,即增大发送窗口大小,从而提高网络吞吐量。
捎带应答
捎带应答是指TCP接收端在返回给发送端的ACK(应答报文)中,除了包含确认序号外,还“捎带”了其他需要发送给发送端的数据或信息。这样做的主要目的是减少网络中的数据包数量,降低通信成本,从而提高传输效率。
例如三次握手中,接收方确认应答后还带上了SYN同步信号发给发送方;
粘包问题
粘包问题是指发送方发送的若干数据包到达接收方时粘成一个数据包,或者接收方接收到的数据包被错误地合并,使得接收方无法正确解析出原始发送的数据包边界。
产生原因
- TCP协议的面向流特性:TCP是一个面向流的协议,它并不保留消息的边界。这意味着TCP会将数据视为一个连续的字节流进行处理,而不是一系列离散的报文。
- TCP的Nagle算法:为了提高网络传输效率,TCP协议实现了Nagle算法。该算法会合并多个小数据包为一个较大的数据包进行发送,从而减少网络中的小数据包数量,降低网络拥塞。然而,这也可能导致粘包问题的出现。
- TCP缓冲区的影响:TCP在发送和接收数据时都会使用缓冲区。如果发送方的缓冲区中有多个数据包待发送,且这些数据包的总大小小于TCP的发送缓冲区大小,那么这些数据包可能会被合并为一个大的数据包发送出去。同样,接收方的缓冲区也可能将多个数据包合并为一个大的数据包进行接收。
- 网络拥塞和延迟:在网络拥塞或延迟较高的情况下,TCP协议可能会采用拥塞控制机制来降低数据发送速率,这也可能导致多个数据包被合并发送。
解决方法
- 定长发送法:
发送端在发送数据时,将每个数据包的大小固定为某个长度(如100字节)。如果数据长度不足该长度,则通过填充空白字节来补齐。
接收端每次从接收缓冲区中读取固定长度的数据作为一个数据包进行处理。 - 尾部标记序列法:
在每个数据包的尾部添加一个特殊的字节序列作为标记,该标记用于标示数据包的结束。
接收端在接收数据时,根据尾部标记来识别数据包的边界。 - 头部标记分步接收法:
在每个数据包的头部添加一个长度字段,用于表示数据包的长度。
接收端首先读取数据包的头部信息,获取数据包的长度,然后根据长度信息从接收缓冲区中读取相应长度的数据作为数据包进行处理。 - 关闭Nagle算法:
在某些情况下,关闭TCP的Nagle算法可以减少粘包问题的发生。但需要注意的是,关闭Nagle算法可能会导致网络传输效率的下降。