一.TCP数据报格式
- 源端口号(Source Port):16位,表示发送方的端口号。
- 目标端口号(Destination Port):16位,表示接收方的端口号。
- 序列号(Sequence Number):32位,表示发送的第一个字节的序列号。
- 确认号(Acknowledgment Number):32位,表示接收方期望接收到的下一个字节的序列号。
- 数据偏移(Data Offset):4位,表示TCP头部的长度,以4字节为单位。
- 保留(Reserved):6位,保留字段,暂未使用。
- 控制位(Control Bits):6位,包括URG、ACK、PSH、RST、SYN、FIN等控制标志。
- 窗口大小(Window Size):16位,表示发送方的接收窗口大小,用于流量控制。
- 校验和(Checksum):16位,用于检验TCP头部和数据的完整性。
- 紧急指针(Urgent Pointer):16位,表示紧急数据的末尾字节的偏移量。
- 选项(Options):可选字段,用于提供额外的功能和控制。
- 填充(Padding):用于填充TCP头部使其对齐到32位。
二.TCP通信时序
三次握手
第一次握手:客户端发送一个带有SYN=1(同步)标志位、序列号Seq=X的数据包给服务器端,客户端进入SYN_SENT状态。
- SYN=1
- ACK=0
- Seq=X
- Ack=0
第二次握手:服务器端收到客户端的请求后,会发送一个带有SYN=1、ACK=1(确认)标志位、序列号Seq=Y、确认号Ack=X+1的数据包给客户端,服务器端进入SYN_RECEIVED状态。
- SYN=1
- ACK=1
- Seq=Y
- Ack=X+1
第三次握手:客户端收到服务器端的确认后,会发送一个带有SYN=0、ACK=1的数据包给服务器端,序列号Seq=X+1、确认号Ack=Y+1。
- SYN=0
- ACK=1
- Seq=X+1
- Ack=Y+1
三次握手完成后,TCP连接建立成功,双方可以开始进行数据传输。每次握手中的SYN和ACK标志位所代表的值如上所示。请注意,初始的序列号是随机选择的,并非写死的数值。
通信
此时,连接已经建立,双方可以通过该连接进行通信。发送方将数据封装在TCP报文段中,并通过已建立的连接发送给接收方。报文段的标志位和字段如下:
- SYN=0
- ACK=1
- 序列号(Seq):发送方当前的序列号
- 确认号(Ack):接收方期望接收到的下一个序列号
接收方收到数据后,发送一个带有确认标志的ACK报文段给发送方,确认已接收到的数据。报文段的标志位和字段如下:
- SYN=0
- ACK=1
- 序列号(Seq):接收方期望接收的下一个序列号
- 确认号(Ack):发送方已经成功接收的最后一个序列号加1
通过以上步骤,发送方和接收方可以进行可靠的数据传输和通信。
四次挥手
四次挥手是指在TCP连接断开时的通信过程,涉及到以下步骤:
发送方发送一个带有FIN标志的报文段给接收方,表示发送方没有数据需要发送了,希望关闭连接。报文段的标志位和字段如下:
- FIN=1(表示不再发送数据)
- ACK=1(表示确认字段有效)
- 序列号(Seq):发送方当前的序列号
- 确认号(Ack):接收方期望接收的下一个序列号
接收方收到FIN报文段后,发送一个带有确认标志的ACK报文段给发送方,表示接收到发送方的关闭请求。报文段的标志位和字段如下:
- FIN=0(表示没有数据要发送)
- ACK=1(表示确认字段有效)
- 序列号(Seq):接收方当前的序列号
- 确认号(Ack):发送方的序列号加1
当接收方确认完所有已接收到的数据后(可能还有未接收到的数据),发送一个带有FIN标志的报文段给发送方,表示接收方也准备关闭连接。报文段的标志位和字段如下:
- FIN=1(表示不再发送数据)
- ACK=1(表示确认字段有效)
- 序列号(Seq):接收方当前的序列号
- 确认号(Ack):发送方的序列号加1
发送方收到接收方的FIN报文段后,发送一个带有确认标志的ACK报文段给接收方,表示已经收到接收方的关闭请求。报文段的标志位和字段如下:
- FIN=0(表示没有数据要发送)
- ACK=1(表示确认字段有效)
- 序列号(Seq):发送方当前的序列号
- 确认号(Ack):接收方的序列号加1
随后,连接就会完全关闭,双方都无法再发送数据。四次挥手的过程是为了确保双方都关闭了连接,并且在关闭之前,已经完成了全部的数据传输和确认。
滑动窗口
TCP由于存在确认应答机制,在一方发出一条消息以后,另一方要发送ACK表明自己收到消息。如果按照下面这种形式,每次收到ACK才发出下一条消息,这种一发一收的效率太低。但是如果客户端不急着接收ACK,可以利用等待ACK的空挡直接发送下一批数据,这样就可以做到短时间内发送多批数据。这就是滑动窗口的基本思想。
[button color=“success” icon=“” url=“https://blog.csdn.net/m0_61210742/article/details/126670292” type=“round”]滑动窗口详情[/button]
三.特殊机制
TCP(传输控制协议)作为一种可靠的传输协议,具有以下一些特殊的机制:
三次握手和四次挥手:TCP建立和终止连接时使用的握手和挥手过程。三次握手用于建立连接,四次挥手用于终止连接,以确保通信的可靠性和完整性。
滑动窗口:TCP使用滑动窗口机制进行流量控制。发送方和接收方通过动态调整窗口大小来控制数据的发送速率,以避免拥塞和数据的丢失。
快速重传:当接收方接收到重复的确认信息时,发送方会快速重传丢失的数据段,而不等待超时定时器触发。这可以加快丢失数据的恢复速度,提高传输效率。
拥塞控制:TCP使用拥塞控制机制来适应网络的拥塞情况。通过动态调整发送速率和窗口大小,TCP可以根据网络拥塞程度来控制数据的发送,以避免拥塞崩溃和网络资源的浪费。
选择确认(Selective Acknowledgment, SACK):TCP可以使用SACK选项来指示接收方成功接收到的非连续数据段,从而使发送方知道哪些数据需要被重传,提高了数据传输的效率。
超时重传:TCP可以使用延迟确认机制来减少确认信息的发送次数。接收方可以等待一段时间,将多个确认信息一起发送,从而降低网络传输开销。
快速重传
快速重传(Fast Retransmit)是TCP协议中一种用于快速检测和修复丢失数据的机制。当接收方收到一个已失序的数据段时,它会发送重复确认(Duplicate Acknowledgment)给发送方,表示接收方已经收到了连续的数据段中的最后一个。如果发送方连续收到接收方的三个重复确认,它就会判断到达该数据段之前的数据段已经丢失,紧接着会立即重传这个数据段,而不必等待超时定时器触发。
快速重传机制的过程如下:
- 发送方发送一系列的数据段给接收方,并等待接收方发送确认信息。
- 接收方收到数据段后,按序存储并发送确认信息。
- 如果接收方收到一个已失序的数据段,它会发送一个重复确认信息给发送方,表示连续接收到的最后一个数据段的序号。
- 发送方收到重复确认信息后,判断之前的数据段已经丢失。
- 发送方会立即重传丢失的数据段,而不必等待超时定时器的触发。
- 重传的数据段到达接收方后,正常处理。
快速重传机制通过监听连续的重复确认信息来尽早发现丢失的数据段,并快速进行重传,避免等待超时定时器的延迟。这样可以更快地修复丢失的数据段,减少数据传输时延,并提高整体的传输效率和数据可靠性。
四.其余尾巴
1.TIME_WAIT状态
TIME_WAIT状态是TCP连接终止过程中的一种状态。当主动关闭连接的一方发送FIN包(发送方希望关闭连接)后,会进入TIME_WAIT状态。TIME_WAIT状态的持续时间通常是2倍的最大报文段生存时间(Maximum Segment Lifetime,MSL)。
TIME_WAIT状态的存在是为了确保连接的可靠关闭和网络的稳定。在TIME_WAIT状态下,可以保证已经关闭的连接在网络中没有残留的数据包,同时为了处理可能延迟到达的数据包而准备。
下面是TIME_WAIT状态的一些特点和作用:
等待挥手完成:TIME_WAIT状态是为了确保连接的双方都完成了挥手过程。在该状态下,主动关闭连接的一方等待一段时间,以便接收对方可能发送的ACK确认报文。
处理延迟数据包:尽管连接已经关闭,但仍然有可能存在延迟到达的数据包。TIME_WAIT状态允许在此期间接收和处理可能再次到达的数据包,并防止这些数据包与后续的连接混淆。
避免连接冲突:在TIME_WAIT状态下,会为相同的本地IP地址和端口分配一个新的唯一的五元组,避免与后续的连接发生冲突。
断开连接的确认:进入TIME_WAIT状态并维持一段时间,可以确保远程主机收到了连接关闭的确认信息,防止出现错误或误解的连接关闭。
需要注意的是,TIME_WAIT状态可能导致一些资源浪费和端口耗尽问题,尤其在短时间内创建大量TCP连接时。为了减轻这种影响,可以调整操作系统的TCP参数,例如减少TIME_WAIT状态的持续时间或启用端口复用等机制。
总之,TIME_WAIT状态在TCP连接关闭过程中起到重要的作用,保证连接的可靠关闭和网络的稳定性,尽管它可能引起一些资源和性能方面的考虑。
2.TCP拆包/粘包问题
TCP拆包和粘包问题是在网络通信中常见的问题,涉及到TCP数据的传输和解析。这些问题是由于TCP是面向字节流的传输协议,而不是面向消息的协议,导致数据在传输过程中可能被拆分或合并。
TCP拆包:TCP拆包是指发送方将消息分割成多个数据包发送,而接收方在接收消息时并非按照原始的数据包边界来接收,导致接收到的数据包与发送方的消息不一致。拆包可能导致接收方无法正确解析消息,或者一个数据包中包含了多个完整的消息。
TCP粘包:TCP粘包是指发送方将两个或多个连续的消息合并成一个数据包发送,而接收方在接收消息时可能会将多个消息组合在一起。粘包会导致接收方无法区分各个消息的边界,或者一个数据包中只包含了部分消息而不完整。
解决TCP拆包和粘包问题可以采用以下几种常见的方法:
消息长度固定:在消息的开头部分增加固定长度的消息长度字段,接收方根据消息长度字段来准确地接收和解析消息,从而避免拆包和粘包问题。
分隔符:在消息的末尾增加特定的分隔符,例如换行符或特殊字符,接收方根据分隔符来分割消息并进行解析。
消息头部:在消息开头部分添加一个固定长度的消息头,包含消息的长度信息,接收方根据消息头中的长度信息来准确地接收和解析消息。
应用层协议:设计应用层协议,明确规定消息的格式、边界和解析方式,使接收方能够准确地根据协议规则解析和处理消息。
在实际开发中,根据具体的需求和情况选择适合的方法来解决TCP拆包和粘包问题。重要的是保证消息的发送方和接收方能够按照一致的规则进行数据分割和解析,以确保数据的准确传输和处理。