理解 TCP 协议中的三次握手及其相关机制是网络通信中的重要一环。让我们一步步了解这个过程吧!😊
什么是三次握手?
三次握手(Three-Way Handshake)是 TCP 协议在建立连接时使用的一个重要过程,用于确保连接的可靠性。它包含以下步骤:
- SYN:客户端向服务器发送一个 SYN(同步序列号)报文,表示希望建立连接。
- SYN-ACK:服务器收到 SYN 后,回应一个 SYN-ACK(同步序列号和确认序列号)报文,表示同意建立连接,并同步序列号。
- ACK:客户端收到 SYN-ACK 后,再发送一个 ACK(确认序列号)报文,确认连接建立。
为什么要三次握手?
三次握手的主要目的是为了确保双方都具备接收和发送数据的能力,并且确认彼此的接收能力。具体来说:
- 确保客户端的发送和服务器的接收功能正常。
- 确保服务器的发送和客户端的接收功能正常。
- 防止旧的连接请求报文被服务器误认为是新的连接请求,造成混乱。
为什么不一次握手?
一次握手不能确保双方都能正常接收和发送数据。例如,客户端发送 SYN 报文后无法确认服务器是否接收到,也无法确认服务器是否能发送数据。缺乏双向确认,无法保证通信的可靠性。
为什么不二次握手?
二次握手无法解决一些潜在的问题,例如旧的 SYN 报文被误认为是新的连接请求,导致资源浪费和错误连接。此外,二次握手也无法完全确认双方的接收和发送能力。
为什么不四次握手?
三次握手已经足够确保连接的可靠性和双方的通信能力。四次握手会增加通信开销,而没有显著的好处。
状态变化
在三次握手过程中,客户端和服务器的状态变化如下:
-
客户端状态:
- 初始状态:CLOSED
- 发送 SYN 后:SYN-SENT
- 收到 SYN-ACK 后:ESTABLISHED
-
服务器状态:
- 初始状态:CLOSED
- 收到 SYN 后:SYN-RECEIVED
- 发送 SYN-ACK 后:SYN-RECEIVED
- 收到 ACK 后:ESTABLISHED
状态变化示意图
sequenceDiagram
participant Client
participant Server
Client->>Server: SYN
Server->>Client: SYN-ACK
Client->>Server: ACK
三次握手过程中的状态标志位变化
| 时间 | 客户端状态 | 服务器状态 | 报文类型 | 说明 |
|---|---|---|---|---|
| t1 | CLOSED | CLOSED | 客户端和服务器初始状态 | |
| t2 | SYN-SENT | LISTEN | SYN | 客户端发送 SYN 请求 |
| t3 | SYN-SENT | SYN-RECEIVED | SYN-ACK | 服务器收到 SYN 并发送 SYN-ACK |
| t4 | ESTABLISHED | ESTABLISHED | ACK | 客户端收到 SYN-ACK 并发送 ACK,连接建立 |
TCP 报头的主要字段:
| 字段名称 | 意义 | 命令行字段 |
|---|---|---|
| 源端口(Source Port) | 发送方的端口号 | sport |
| 目标端口(Destination Port) | 接收方的端口号 | dport |
| 序列号(Sequence Number) | 数据段的序列号,用于数据重组和流量控制 | seq |
| 确认号(Acknowledgment Number) | 确认接收到的数据的下一个序列号 | ack |
| 数据偏移(Data Offset) | TCP 报头的长度,指示数据开始的地方 | offset |
| 保留字段(Reserved) | 保留供将来使用,目前必须设置为0 | reserved |
| 控制标志(Flags) | 控制数据段的标志(如 SYN, ACK, FIN 等) | flags |
| 窗口大小(Window Size) | 接收方愿意接收的窗口大小,用于流量控制 | window |
| 校验和(Checksum) | 用于检验数据段的完整性 | checksum |
| 紧急指针(Urgent Pointer) | 紧急数据的指针,指示紧急数据的结束位置 | urgptr |
| 选项(Options) | 可选字段,用于扩展 TCP 的功能 | options |
| 填充(Padding) | 用于确保 TCP 报头是32位的整数倍,填充无意义的数据 | padding |
TCP传输过程常见的问题
出错
- 校验和
- 重传机制
重复
- 序列号和确认号机制
- 窗口大小控制
- 超时重传和快速重传
丢失
- 超时重传机制
- 快速重传机制
- 选择性确认
失序
- 选择性确认
什么是出错?
出错是指在数据传输过程中,数据被篡改或丢失,导致接收方收到错误的数据。出错通常是由物理层和数据链路层的干扰引起的。
状态位变化与解决方法
出错时,接收方会检测到数据的校验和不匹配,丢弃错误数据并请求重传。解决方法是使用校验和(Checksum)和重传机制。
校验和(Checksum)
校验和是一种用于检测数据传输过程中错误的简单机制。它通过对数据执行特定的计算生成一个数值,接收方也会进行同样的计算并与发送方的校验和进行比较,如果两者不一致,就说明数据在传输过程中发生了错误。
校验和计算过程
-
发送方:
- 将数据分成若干个部分(通常为16位)。
- 将这些部分加在一起,得到一个数值。
- 计算这个数值的反码(所有位取反),作为校验和。
- 将数据和校验和一起发送给接收方。
-
接收方:
- 接收到数据和校验和。
- 使用同样的方法计算接收到的数据的校验和。
- 将接收方计算出的校验和与发送方发送的校验和进行比较。
- 如果两者一致,说明数据传输没有错误;否则,说明数据在传输过程中发生了错误,需要请求重传。
重传机制
重传机制用于在接收方检测到数据传输错误时,请求发送方重新发送数据。TCP 使用两种主要的重传机制:
-
超时重传:
- 发送方在发送数据后,会启动一个定时器。
- 如果在定时器超时前没有收到接收方的确认报文,发送方会认为数据丢失或出错,进行重传。
-
快速重传:
- 接收方在检测到数据包出错或丢失时,会立即发送重复的 ACK 报文。
- 当发送方收到三个连续的重复 ACK 报文时,立即重传对应的数据包,而无需等待超时。
在使用校验和(Checksum)和重传机制的过程中,TCP 报头(Header)中的一些字段会发生变化。这些字段主要包括序列号(Sequence Number)、确认号(Acknowledgment Number)、校验和(Checksum)等。让我们详细了解这些字段在数据传输过程中的变化情况。
校验和的计算和使用
校验和用于验证数据在传输过程中是否发生错误。它是对 TCP 报头、数据以及伪报头(包含源 IP 地址、目的 IP 地址、协议类型和 TCP 报文长度)的一种计算结果。伪报头仅用于计算校验和,不包含在实际的 TCP 报头中。
校验和计算过程
- 伪报头:包括源 IP 地址、目的 IP 地址、协议类型(TCP 为 6)和 TCP 报文长度。
- 报头和数据:包括 TCP 报头和数据。
- 计算和校验:
- 将伪报头、报头和数据视为若干个 16 位数值。
- 将这些数值加在一起,如果有进位则将进位加到结果中。
- 对结果取反,得到校验和。
- 发送方将计算得到的校验和填入 TCP 报头中的校验和字段。
- 接收方计算接收到的数据的校验和,并与报头中的校验和比较,以验证数据完整性。
重传机制
在重传机制中,TCP 报头中的序列号和确认号会发生变化,以确保数据的可靠传输。
超时重传和快速重传
- 超时重传:如果发送方在一定时间内没有收到接收方的确认,发送方会重新发送数据。
- 快速重传:当接收方检测到数据包出错或丢失时,会发送重复的 ACK 报文。发送方在收到三个连续的重复 ACK 后,会立即重传相应的数据包。
报头字段的变化
例子:校验和和重传机制的工作过程
假设客户端发送一个数据包给服务器,数据包的序列号为 1001,数据内容为 "Hello"。以下是报头字段在不同阶段的变化:
- 初始发送:
-
发送方(客户端):
- 计算数据 "Hello" 的校验和,假设得到校验和为
0x1234。 - 发送数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x1234, 数据="Hello"]。
- 计算数据 "Hello" 的校验和,假设得到校验和为
-
接收方(服务器):
- 接收到数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x1234, 数据="Hello"]。 - 计算接收数据 "Hello" 的校验和,假设计算结果为
0x1234。 - 比较接收到的校验和
0x1234与计算得到的校验和0x1234,一致,数据正确。 - 发送 ACK 包 [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1002, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x5678]。
- 接收到数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
- 重传过程(数据包出错):
-
发送方(客户端):
- 发送数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x1234, 数据="Hello"]。 - 启动定时器。
- 发送数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
-
接收方(服务器):
- 接收到错误数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x1234, 数据="Hxllo"]。 - 计算接收数据 "Hxllo" 的校验和,假设计算结果为
0x5678。 - 比较接收到的校验和
0x1234与计算得到的校验和0x5678,不一致,数据出错。 - 丢弃错误数据包,发送重复的 ACK 包 [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1001, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x5678]。
- 接收到错误数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
-
发送方(客户端):
- 收到重复的 ACK 包 [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1001, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x5678]。 - 重传数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x1234, 数据="Hello"]。 - 再次启动定时器。
- 收到重复的 ACK 包 [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1001, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
- 重传成功:
-
接收方(服务器):
- 接收到重传数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x1234, 数据="Hello"]。 - 计算接收数据 "Hello" 的校验和,假设计算结果为
0x1234。 - 比较接收到的校验和
0x1234与计算得到的校验和0x1234,一致,数据正确。 - 发送 ACK 包 [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1002, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x5678]。
- 接收到重传数据包 [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
-
发送方(客户端):
- 收到 ACK 包 [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1002, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
0x5678]。 - 停止定时器,确认数据包成功传输。
- 收到 ACK 包 [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1002, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=
报头字段变化表格
| 时间 | 客户端报头 | 服务器报头 | 说明 |
|---|---|---|---|
| t1 | [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=0x1234] | 客户端发送数据 | |
| t2 | [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=0x1234] | 服务器接收数据,校验正确 | |
| t3 | [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1002, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=0x5678] | 服务器发送确认 | |
| t4 | [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=0x1234] | 客户端重传数据 | |
| t5 | [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=0x1234] | 服务器接收重传数据,校验正确 | |
| t6 | [源端口=80, 目的端口=5000, 序列号=2001, 确认号=1002, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=0x5678] | 服务器发送确认 | |
| t7 | [源端口=5000, 目的端口=80, 序列号=1001, 确认号=0, 数据偏移=5, 控制标志=ACK, 窗口大小=4096, 校验和=0x1234] | 客户端停止重传,确认成功 |
通过上述步骤和表格,我们可以清晰地看到在使用校验和和重传机制过程中,TCP 报头字段是如何变化的。这些机制确保了数据在网络传输中的完整性和可靠性。😊
什么是重复?
重复是指同一个数据包被多次发送,接收方收到多份相同的数据包。这通常是由于网络故障或重传机制引起的。
状态位变化与解决方法
接收方可以通过序列号检测到重复数据包,并丢弃重复数据,确保数据的唯一性。
解决 TCP 通信中的重复数据包主要通过以下方法实现:
- 序列号和确认号机制
- 窗口大小控制
- 超时重传和快速重传
我们将详细介绍这些方法以及在过程中 TCP 报头的变化。
1. 序列号和确认号机制
原理
TCP 使用序列号(Sequence Number)来标识数据包的顺序。每个数据包都有一个唯一的序列号,接收方通过序列号来识别和丢弃重复的数据包。确认号(Acknowledgment Number)用于确认已接收的数据包,并告知发送方数据已经正确到达。
过程
- 发送方:发送带有序列号的数据包,并等待接收方的确认。
- 接收方:接收数据包,检查序列号。如果是新数据包,则处理并发送 ACK;如果是重复数据包,则丢弃并发送重复的 ACK。
TCP 报头变化
-
发送方发送数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
接收方接收数据包,发送 ACK:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 80 | 5000 | 0 | 1002 | 5 | 0x5678 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
发送方未收到 ACK,重传数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+
2. 窗口大小控制
原理
TCP 使用窗口大小(Window Size)来控制发送方可以发送的未确认数据的最大数量。通过调整窗口大小,接收方可以有效地控制数据流,避免发送方过快发送数据而导致网络拥塞。
过程
- 发送方:根据接收方的窗口大小,决定可以发送的数据量。
- 接收方:根据接收能力,调整窗口大小并通知发送方。
TCP 报头变化
-
发送方发送数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
接收方调整窗口大小,发送 ACK:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 80 | 5000 | 0 | 1002 | 5 | 0x5678 | 2048 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+
3. 超时重传和快速重传
原理
当发送方在一定时间内没有收到 ACK 时,会触发超时重传。快速重传是指发送方在收到三个连续的重复 ACK 时,立即重传数据包,而不等待超时。
过程
- 发送方:发送数据包,启动定时器,等待接收方的 ACK。如果超时未收到 ACK 或收到重复的 ACK,立即重传数据包。
- 接收方:接收到数据包后,发送 ACK。如果数据包有错误或丢失,发送重复的 ACK。
TCP 报头变化
-
发送方发送数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
接收方发送 ACK:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 80 | 5000 | 0 | 1002 | 5 | 0x5678 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
发送方未收到 ACK,重传数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
接收方发送重复的 ACK:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 80 | 5000 | 0 | 1002 | 5 | 0x5678 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+
通过上述方法和过程,TCP 能有效检测和处理重复数据包,保证数据传输的准确性和可靠性。这些机制确保了在数据传输过程中,尽可能减少重复数据包带来的影响,提高通信效率和数据完整性。
什么是丢失?
丢失是指数据包在传输过程中被丢弃,接收方未收到数据包。这可能是由于网络拥塞或故障引起的。
状态位变化与解决方法
丢失的数据包会导致接收方未能确认数据。发送方在超时后会重新发送数据包。
在 TCP 通信中,数据包丢失是一个常见问题,通常通过以下几种方法来解决:
- 超时重传机制(Timeout Retransmission)
- 快速重传机制(Fast Retransmit)
- 选择性确认(Selective Acknowledgment, SACK)
我们将详细介绍这些方法及其过程,并说明在过程中 TCP 报头的变化。
1. 超时重传机制
原理
当发送方在设定的时间内未收到接收方的确认(ACK),就会重传数据包。这是最基本的一种重传机制。
过程
- 发送方:发送数据包,并启动定时器。
- 接收方:接收数据包后,发送 ACK。
- 发送方:如果在定时器超时前没有收到 ACK,重传数据包。
TCP 报头变化
-
发送方发送数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
接收方发送 ACK(如果接收到数据包):
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 80 | 5000 | 0 | 1002 | 5 | 0x5678 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
发送方未收到 ACK,重传数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+
2. 快速重传机制
原理
快速重传机制在接收方收到三个连续的重复 ACK 时,发送方立即重传数据包,而不等待超时。这减少了等待时间,提高了数据传输效率。
过程
- 发送方:发送数据包,等待 ACK。
- 接收方:如果数据包有丢失,接收方会发送重复的 ACK。
- 发送方:收到三个重复的 ACK 后,立即重传丢失的数据包。
TCP 报头变化
-
发送方发送数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
接收方发送重复的 ACK:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 80 | 5000 | 0 | 1001 | 5 | 0x5678 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
发送方收到三个重复的 ACK,立即重传数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+
3. 选择性确认(SACK)
原理
选择性确认允许接收方告知发送方哪些具体数据段已经成功接收,哪些还需要重传。这种机制在数据包丢失率较高的网络环境中非常有效。
过程
- 发送方:发送数据包,等待 ACK。
- 接收方:接收数据包后,发送选择性确认,标识已成功接收的段。
- 发送方:根据选择性确认,重传丢失的数据段。
TCP 报头变化
-
发送方发送数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
接收方发送选择性确认:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 80 | 5000 | 0 | 1002 | 5 | 0x5678 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+ -
发送方根据选择性确认,重传丢失的数据包:
+---------+---------+----------+----------+-----------+----------+--------+--------+ | Source | Dest. | Sequence | Ack | Data | Checksum | Window | Urgent | | Port | Port | Number | Number | Offset | | Size | Pointer| +---------+---------+----------+----------+-----------+----------+--------+--------+ | 5000 | 80 | 1001 | 0 | 5 | 0x1234 | 4096 | 0 | +---------+---------+----------+----------+-----------+----------+--------+--------+
总结
通过超时重传、快速重传和选择性确认,TCP 能够有效解决数据包丢失的问题,确保数据传输的可靠性和完整性。每种方法在不同网络条件下都有其优点,综合使用这些方法,可以大大提高 TCP 通信的效率和稳定性。
什么是失序?
失序是指数据包按错序列到达接收方,接收方无法按正确顺序重组数据。这通常是由于网络路径的差异或多路径传输引起的。
状态位变化与解决方法
接收方会缓存失序的数据包,并等待缺失的数据包到达后再进行重组。
真实例子:失序过程中的状态标志位变化
| 时间 | 客户端状态 | 服务器状态 | 报文类型 | 说明 |
|---|---|---|---|---|
| t1 | ESTABLISHED | ESTABLISHED | DATA(seq=1) | 客户端发送数据包 1 |
| t2 | ESTABLISHED | ESTABLISHED | DATA(seq=3) | 客户端发送数据包 3 |
| t3 | ESTABLISHED | ESTABLISHED | DATA(seq=2) | 客户端发送数据包 2 |
| t4 | ESTABLISHED | ESTABLISHED | 服务器缓存数据包 3,等待数据包 2 | |
| t5 | ESTABLISHED | ESTABLISHED | ACK | 数据包 2 到达,服务器按顺序重组并确认 |
总结
TCP 三次握手通过序列号和确认机制,确保了连接的可靠性和双方的通信能力。在数据传输过程中,通过各种检测和重传机制,解决了出错、重复、丢失和失序等问题。😄