TCP协议详解
2025-03-11 16:11:22 0 举报
AI智能生成
根据计算机网络第八版tcp部分做的思维导图,包括Tcp概述,首部结构,可靠传输,流量控制,拥塞控制,运输连接管理,常见问题整理等八大分支。
作者其他创作
大纲/内容
TCP协议概述
TCP最主要特点
TCP 是面向连接的运输层协议,在无连接的、不可靠的 IP 网络服务基础之上提供可靠交付的服务。为此,在 IP 的数据报服务基础之上,增加了保证可靠性的一系列措施。
TCP 是面向连接的运输层协议
每一条 TCP 连接只能有两个端点 (endpoint),每一条 TCP 连接只能是点对点的(一对一)
TCP 提供可靠交付的服务
TCP 提供全双工通信
面向字节流
- TCP 中的“流”(stream) 指的是流入或流出进程的字节序列。
- 面向字节流:虽然应用程序和 TCP 的交互是一次一个数据块,但 TCP 把应用程序交下来的数据看成仅仅是一连串无结构的字节流。
- TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系。
- 但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。
TCP的连接
TCP 把连接作为最基本的抽象
套接字 (socket)
TCP 连接,IP 地址,套接字
TCP 连接就是由协议软件所提供的一种抽象。
TCP 连接的端点是抽象的套接字,即(IP 地址:端口号)。
同一个 IP 地址可以有多个不同的 TCP 连接。
同一个端口号也可以出现在多个不同的 TCP 连接中。
TCP报文段的首部格式
源端口与目标端口
源端口和目的端口:各占 2 字节。端口是运输层与应用层的服务接口。
运输层的复用和分用功能通过端口实现。
运输层的复用和分用功能通过端口实现。
序号
占 4 字节。TCP 连接中传送的数据流中的每一个字节都有一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。
确认号
确认号:占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。
若确认号 = N,则表明:到序号 N – 1 为止的所有数据都已正确收到。
数据偏移
(即首部长度):占 4 位,指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。单位是 32 位字(以 4 字节为计算单位)。
保留
占6位,保留为今后使用,目前应值为0
紧急URG
控制位。当 URG = 1 时,表明紧急指针字段有效,告诉系统此报文段中有紧急数据,应尽快传送 (相当于高优先级的数据)。
确认ACK
控制位。只有当 ACK =1 时,确认号字段才有效。当 ACK =0 时,确认号无效。
推送PSH
控制位。接收 TCP 收到 PSH = 1 的报文段后,就尽快(即“推送”向前)交付接收应用进程,而不再等到整个缓存都填满后再交付。
复位RST
控制位。当 RST=1 时,表明 TCP 连接中出现严重差错(如主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
同步SYN
控制位。
同步 SYN = 1 表示这是一个连接请求或连接接受报文。
当 SYN = 1,ACK = 0 时,表明这是一个连接请求报文段。
当 SYN = 1,ACK = 1 时,表明这是一个连接接受报文段。
同步 SYN = 1 表示这是一个连接请求或连接接受报文。
当 SYN = 1,ACK = 0 时,表明这是一个连接请求报文段。
当 SYN = 1,ACK = 1 时,表明这是一个连接接受报文段。
终止FIN
控制位。用来释放一个连接。
FIN=1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
FIN=1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
窗口
占 2 字节。
窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。
窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。
校验和
占 2 字节。检验和字段检验的范围包括首部和数据这两部分。
在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。
在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。
在计算检验和时,临时把 12 字节的“伪首部”和 TCP 报文段连接在一起。伪首部仅仅是为了计算检验和。
紧急指针
占 2 字节。在 URG = 1时,指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据),指出了紧急数据的末尾在报文段中的位置。
假如紧急指针为50,就代表数据包从1-50个字节是需要优先处理的
选项
长度可变,最长可达40字节
Tcp Options字段的一般数据结构:Kind(1字节)+Length(1字节)+Info(n字节)
选项的第一个字段kind说明选项的类型。有的TCP选项没有后面两个字段,仅包含1字节的kind字段。第二个字段length(如果有的话)指定该选项的总长度,该长度包括kind字段和length字段占据的2字节。第三个字段info(如果有的话)是选项的具体信息。常见的TCP选项有7种
主要选项解释
MSS
MSS (Maximum Segment Size)是 TCP 报文段中的数据字段的最大长度。
数据字段加上 TCP 首部才等于整个的 TCP 报文段。所以,MSS是“TCP 报文段长度减去 TCP 首部长度”。
数据字段加上 TCP 首部才等于整个的 TCP 报文段。所以,MSS是“TCP 报文段长度减去 TCP 首部长度”。
最大报文段长度 MSS (Maximum Segment Size) 是每个 TCP 报文段中的数据字段的最大长度。
与接收窗口值没有关系
MTU & MSS
MSS大小的选择
不能太小
网络利用率降低。
例如:仅 1 个字节。利用率就不会超过1/41。
例如:仅 1 个字节。利用率就不会超过1/41。
不能太大
- 开销增大。
- IP 层传输时要分片,终点要装配。
- 分片传输出错时,要整个分组。
应尽可能大
- 只要在 IP 层传输时不再分片。
- 默认值= 536 字节。
- 报文段长度 = 536 + 20 = 556 字节。
- IP 数据报长度 = 576 字节。
窗口扩大
什么是TCP窗口
TCP 采用流量控制(Flow Control)机制,使用滑动窗口(Sliding Window)来管理数据的发送和接收。
TCP 头部中的 窗口大小字段(Window Size) 指定了接收方当前可以接受的最大数据量,用于控制数据流,以防止接收方被发送方淹没。
窗口大小字段(16 位)最大能表示的值是 65,535(2¹⁶ - 1)字节,即约 64 KB,这个值在现代高速网络环境下严重不足,因此 TCP 提供了 Window Scale 选项来扩展窗口大小。
TCP 头部中的 窗口大小字段(Window Size) 指定了接收方当前可以接受的最大数据量,用于控制数据流,以防止接收方被发送方淹没。
窗口大小字段(16 位)最大能表示的值是 65,535(2¹⁶ - 1)字节,即约 64 KB,这个值在现代高速网络环境下严重不足,因此 TCP 提供了 Window Scale 选项来扩展窗口大小。
Window Scale选项的作用
Window Scale(窗口缩放)选项用于扩展 TCP 窗口的大小,使其支持最大 1GB(2³⁰ 字节)的窗口,而不是 64KB。
- 在 TCP 头部,窗口大小字段 只有 16 位,最大值为 65,535 字节(64KB)。
- 但是,高带宽-时延(BDP,Bandwidth Delay Product)网络环境下,64KB 可能会严重限制吞吐量。
- Window Scale 选项通过左移窗口大小字段,扩展了窗口的范围,最大可达 1GB。
Window Scale 选项的工作原理
TCP 窗口扩展通过一个"缩放因子"(Scaling Factor)来扩大窗口的大小:
- Window Scale 选项定义了一个因子 n(0 ≤ n ≤ 14),窗口大小的计算方式变为:
- 实际窗口大小=TCP 头部窗口大小字段×2^𝑛
- 其中:
- TCP 头部的窗口字段(Window Size) 仍然存储 16 位的值(最大 65,535)。
- 缩放因子 n 在 Window Scale 选项中存储,范围是 0 到 14。
- 最终的实际窗口大小最大可达 65,535 × 2¹⁴ = 1,073,725,440 字节(即 1GB)。
Window Scale 选项的格式
Kind Length Shift Count
+------+--------+-------------+
| 3 | 3 | n |
+------+--------+-------------+
+------+--------+-------------+
| 3 | 3 | n |
+------+--------+-------------+
字段解释:
- Kind = 3:表示这是 Window Scale 选项。
- Length = 3:整个字段占用 3 字节。
- Shift Count:即缩放因子 n,接收方必须用 2^n 进行窗口扩展计算。
Window Scale 选项的协商(在 TCP 三次握手时)
- Window Scale 选项只能在 TCP 三次握手期间协商,后续不能更改。
- 双方都必须在 SYN 报文中发送 Window Scale 选项,否则不会启用。
- 每一方独立协商自己的窗口缩放因子。
时间戳
TCP 序列号回绕
TCP 序列号的基本概念
- TCP 采用 字节流传输,每个字节都会被分配一个 序列号(Sequence Number, SEQ)。
- TCP 头部中的 序列号字段是 32 位的,意味着它的取值范围是:0∼2^32−1=4,294,967,295(4GB)
- 当序列号达到最大值后,下一个序列号会从 0 重新开始,这就称为 序列号回绕(Sequence Number Wrap Around)。
序列号回绕的影响
(1) 旧数据包可能被误认为是新数据
- TCP 可能会误把旧的、延迟的报文当作新的数据包处理,导致数据错误。
- 例如:
- 发送方发送了 4GB 的数据,序列号回绕。
- 由于某些网络设备缓存了旧数据包,并在稍后才送达。
- TCP 可能会误认为这个 "旧数据" 是新的有效数据,从而导致应用程序解析错误。
(2) ACK 可能导致错误的确认
- 如果序列号回绕且 ACK 没有正确匹配新数据,可能导致接收方丢弃正确的报文,甚至发生 TCP 拥塞控制错误。
什么时候容易发生序列号回绕
序列号回绕主要在 高带宽(Gbps 级别)网络 中更容易发生。
计算 TCP 序列号回绕的时间
作用
精确计算 RTT(往返时间,Round-Trip Time)
传统的 RTT 计算方式
- TCP 通过 测量 ACK 报文的往返时间 来估算 RTT。
- 但 ACK 不是逐个确认每个数据包,所以 RTT 计算可能不准确。
基于时间戳的 RTT 计算
- 发送方在数据包的 TSval 字段填入当前时间戳。
- 接收方收到数据后,在 ACK 报文的 TSecr 字段中回显 TSval 的值。
- 发送方收到 ACK 后,计算当前时间戳与 TSecr 之间的差值,即为 RTT。
示例
假设:
- 发送方 发送数据包,TSval = 1000。
- 接收方 收到后,在 ACK 报文中填充 TSecr = 1000。
- 发送方 收到 ACK,此时当前 TSval = 1200,则 RTT 计算为:
- RTT=1200−1000=200ms
优点
✅ 避免了传统 TCP RTT 计算中的“确认延迟”问题。
✅ 可以对每个数据包独立计算 RTT,减少波动,提高准确性。
✅ 支持更好的 TCP 拥塞控制(如 TCP Reno、TCP Vegas 等)
✅ 可以对每个数据包独立计算 RTT,减少波动,提高准确性。
✅ 支持更好的 TCP 拥塞控制(如 TCP Reno、TCP Vegas 等)
防止 TCP 序列号回绕(PAWS,Protect Against Wrapped Sequence numbers)
问题
- TCP 序列号是 32 位,最大值 4,294,967,295(4GB 数据)。
- 在 高带宽网络(如 10Gbps)下,短时间内就可能用完序列号并回绕。
- 旧的数据包可能会和新的数据包使用相同的序列号,导致数据错乱。
时间戳解决方案(PAWS 机制)
- 由于时间戳值是单调递增的,TCP 可以检查 TSval 来区分新旧数据包:
- 如果一个 TCP 报文的时间戳比当前接收窗口中的时间戳还小,则丢弃该报文(表示它是旧的)。
- 这样可以防止序列号回绕导致的错误数据接收。
PAWS 机制的适用范围
✅ 数据包(包含数据的 TCP 段)
✅ SYN 片段(用于新连接)
❌ 不适用于纯 ACK(确认包)(因为 ACK 可能丢失,需要允许重复 ACK)
✅ SYN 片段(用于新连接)
❌ 不适用于纯 ACK(确认包)(因为 ACK 可能丢失,需要允许重复 ACK)
为什么时间戳可以作为判断依据
- 由系统启动时间计算(通常是毫秒级或 10ms 级)。
- 单调递增(不会回绕)。
- 时间戳回绕周期远远大于序列号回绕周期(例如,时间戳回绕需要 49.7 天,而 10Gbps 下序列号回绕只需要 3.44 秒)。
格式
Kind Length TS Value (TSval) TS Echo Reply (TSecr)
+------+--------+------------------+------------------+
| 8 | 10 | 32 bits | 32 bits |
+------+--------+------------------+------------------+
+------+--------+------------------+------------------+
| 8 | 10 | 32 bits | 32 bits |
+------+--------+------------------+------------------+
- Kind = 8:表示这是时间戳选项。
- Length = 10:整个字段占 10 个字节(1 字节 Kind + 1 字节 Length + 8 字节时间戳)。
- TS Value(TSval,时间戳值):由 发送方填充的当前时间戳,通常是 TCP 连接启动以来的时间(单位:毫秒)。
- TS Echo Reply(TSecr,时间戳回显):回显对方发送的 TSval 值,用于 RTT 计算。
时间戳选项的协商
时间戳选项只能在 TCP 三次握手期间协商
- 如果双方都在 SYN 报文中发送了时间戳选项,则 TCP 连接会启用该选项。
- 如果 任意一方没有发送,则该连接不会使用时间戳选项。
TCP 三次握手的时间戳选项示例
假设:
客户端使用 TSval = 10000
服务器使用 TSval = 20000
客户端使用 TSval = 10000
服务器使用 TSval = 20000
客户端 -> 服务器 [SYN, TSval=10000]
服务器 -> 客户端 [SYN-ACK, TSval=20000, TSecr=10000]
客户端 -> 服务器 [ACK, TSval=10200, TSecr=20000]
服务器 -> 客户端 [SYN-ACK, TSval=20000, TSecr=10000]
客户端 -> 服务器 [ACK, TSval=10200, TSecr=20000]
在后续的通信中:
服务器会回显客户端的 TSval 值作为 TSecr。
客户端会回显服务器的 TSval 值作为 TSecr。
服务器会回显客户端的 TSval 值作为 TSecr。
客户端会回显服务器的 TSval 值作为 TSecr。
TCP 时间戳的实际应用
高带宽-时延网络
在高带宽、长 RTT(如卫星通信、跨洲数据传输)的网络环境下,时间戳选项可以:
- 更精确地计算 RTT,提高 TCP 拥塞控制的准确性。
- 防止序列号回绕,避免错误的数据接收。
现代 TCP 拥塞控制算法
现代 TCP 拥塞控制算法(如 TCP BBR、TCP CUBIC)都依赖于准确的 RTT 估算,时间戳选项是这些算法的重要组成部分。
填充
使整个tcp首部长度是4字节的整数倍
TCP可靠传输机制原理
滑动窗口协议
发送窗口与接收窗口
发送窗口大小调整
接收窗口大小通告
滑动窗口工作原理
数据发送流程
数据确认流程
超时重传机制
流量控制策略
慢开始算法
拥塞避免算法
快重传与快恢复算法
差错检测与重传
校验和计算
校验和算法
校验和位置
ACK报文丢失处理
超时重传
重复ACK触发重传
数据报文丢失处理
超时重传策略
SACK选项应用
拥塞控制机制
慢开始与拥塞避免
慢开始阶段特点
拥塞避免阶段特点
快重传与快恢复
快重传触发条件
快恢复操作过程
AIMD算法原理
加法增大阶段
乘法减小阶段
停止等待协议
无差错情况
A发送过去,B再发一个确认包回来;如此反复知道A发完
超时重传
A发送过去,B没有接收到,或者B接收到,没有回复确认包给A,此时,超过一定时间,A就会重传这个B没有收到的数据包
确认丢弃
当A给B发送数据包时候,B收到了数据包,但是B再发一个确认包给A时候,丢失了,或者超时了,此时A就会超时重新发送数据包给B,当B收到A在次发送的数据包时候,丢弃掉A原来发过的一模一样的数据包,B确认重传一个确认包给A
确认迟到
当A给B发送数据包时候,B收到了,但是由于B的回复确认数据包给A时候迟到了,那么即使,A收到了确认包,但是什么也不会做,意思是,不会再发送下一个包给B了,因为它迟到了,并且在它迟到前,已经完成了发送下一个包给B了,所以确认迟到的包是不会做任何事情
停止等待协议要点
- 停止等待。发送方每次只发送一个分组。在收到确认后再发送下一个分组。
- 暂存:在发送完一个分组后,发送方必须暂存已发送的分组的副本,以备重发。
- 编号。对发送的每个分组和确认都进行编号。
- 超时重传。发送方为发送的每个分组设置一个超时计时器。若超时计时器超时位收到确认,发送方会自动超时重传分组。
- 超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一些,防止不必要的重传。
- 简单,但信道利用率太低。
连续ARQ协议
发送窗口
发送方维持一个发送窗口,位于发送窗口内的分组都可被连续发送出去,而不需要等待对方的确认。
发送窗口滑动
发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置
累积确认
接收方对按序到达的最后一个分组发送确认,表示:到这个分组为止的所有分组都已正确收到了
TCP可靠传输的实现
以字节为单位的滑动窗口
- TCP 使用流水线传输和滑动窗口协议实现高效、可靠的传输。
- TCP 的滑动窗口是以字节为单位的。
- 发送方 A 和接收方 B 分别维持一个发送窗口和一个接收窗口。
- 发送窗口:在没有收到确认的情况下,发送方可以连续把窗口内的数据全部发送出去。凡是已经发送过的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用。
- 接收窗口:只允许接收落入窗口内的数据。
窗口的滑动
- A 根据 B 给出的窗口值,构造出自己的发送窗口。
- 发送窗口里面的序号表示允许发送的序号。
- 窗口越大,发送方就可以在收到对方确认之前连续发送更多的数据,因而可能获得更高的传输效率。
特殊情景:发送窗口已满
发送缓存与发送窗口
接收缓存与接收窗口
注意事项
发送窗口是根据接收窗口设置的,但在同一时刻,发送窗口并不总是和接收窗口一样大(因为有一定的时间滞后)。
TCP 标准没有规定对不按序到达的数据应如何处理。通常是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程。
TCP 要求接收方必须有累积确认的功能,以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。但接收方不应过分推迟发送确认,否则会导致发送方不必要的重传,捎带确认实际上并不经常发生。
超时重传时间的选择
RTT
RTT(Round-Trip Time) 是指从发送端发送数据到接收端,接收端处理后返回 ACK 确认的总时间。简单来说,就是一个数据包从发送方到达接收方,并返回确认的时间。
RTT=ACK 到达时间−数据包发送时间
RTT=ACK 到达时间−数据包发送时间
RTO
RTO(Retransmission Timeout)是 TCP 在未收到 ACK 时,重传数据之前等待的时间。
如果超时仍未收到确认,TCP 就会 重传数据,并 调整 RTO 以适应当前网络情况。
RTO 需要 动态调整,如果设置太短,会导致不必要的重传;如果太长,则会影响 TCP 传输效率。
如果超时仍未收到确认,TCP 就会 重传数据,并 调整 RTO 以适应当前网络情况。
RTO 需要 动态调整,如果设置太短,会导致不必要的重传;如果太长,则会影响 TCP 传输效率。
RTO的计算方式
⚠ RTO 最低不能小于 1 秒,最大不能超过 60 秒(RFC 规定)。
Karn 算法
Karn 算法的背景
TCP 需要动态调整超时重传时间(RTO, Retransmission Timeout),而 RTO 的计算依赖于 往返时延(RTT, Round-Trip Time)。TCP 通过测量 RTT 来计算 RTO,但在某些情况下,测量的 RTT 可能是不准确的。
问题:如果一个数据包超时重传了,应该如何计算 RTT?
Karn 算法避免使用重传数据包的 ACK 来计算 RTT,以防止误导 RTO 估算。
问题:如果一个数据包超时重传了,应该如何计算 RTT?
- TCP 发送数据后,如果没有收到 ACK,它会在 RTO 超时时重传。
- 但是,收到的 ACK 可能是针对原始发送的数据包,也可能是针对重传的数据包。
- 此时,RTT 计算就会出现不确定性,因为无法区分 ACK 是响应哪个数据包的。
Karn 算法避免使用重传数据包的 ACK 来计算 RTT,以防止误导 RTO 估算。
Karn 算法的核心规则
Karn 算法:
如果一个数据包被重传,就不更新 RTT 计算(因为无法区分 ACK 是针对原始数据还是重传数据)。
缺陷:
当报文段的时延突然增大很多时,在原来得出的重传时间内,不会收到确认报文段,于是就重传报文段。但根据 Karn 算法,不考虑重传的报文段的往返时间样本。这样,超时重传时间就无法更新,造成很多不必要的重传。
修正的Karn 算法:
如果发生了重传,则 TCP 使用 “指数退避” 来增加 RTO,即:RTO=RTO×2
Karn 算法如何工作
✅ 正常情况下(无重传):
- 发送数据包 SEQ=1000,记录发送时间 T1。
- 接收方收到后,发送 ACK=1500,到达时间 T2。
- 计算 RTT:RTT=T2−T1
- 根据 RTT 更新 RTO。
- 发送 SEQ=1000,但 ACK 丢失或延迟。
- 超时后,发送方重传 SEQ=1000。
- 接收方发送 ACK=1500(但无法确定这个 ACK 是确认原始数据还是重传数据)。
- Karn 算法:不使用该 ACK 来计算 RTT,防止 RTT 误判。
为什么 Karn 算法很重要
如果 TCP 错误地使用重传 ACK 来计算 RTT,可能导致 RTO 过小:
- 这可能引发不必要的超时重传,增加网络负载。
- 使 TCP 误以为网络状况良好,导致过早重传,进一步加剧拥塞。
Karn 算法的作用
✅ 避免 RTT 计算被重传干扰,保证 RTO 估算准确。
✅ 结合指数退避,减少过度重传,防止网络进一步恶化。
选择确认 SACK
为什么需要 SACK
在传统 TCP 累积确认(Cumulative Acknowledgment)机制下:
- TCP 只能确认按序接收的数据,如果中间有丢包,接收方只能发送最后连续收到的数据的 ACK。
- 问题:如果有多个数据包丢失,发送方必须重传丢失的数据以及已经成功收到的数据,导致浪费带宽,影响 TCP 效率。
示例(没有 SACK 的情况):
发送方发送:
SEQ=1000 → 2000 → 3000 → 4000 → 5000
假设 SEQ=2000 丢失,接收方收到:
SEQ=1000 ✔ → [丢失] → 3000 ✔ → 4000 ✔ → 5000 ✔
但 接收方只能发送 ACK=2000(表示期望下一个字节),而不能告诉发送方 "3000, 4000, 5000 已经收到"。
发送方 只能重传 2000、3000、4000、5000,尽管 3000、4000、5000 已经正确到达,导致 浪费带宽。
发送方发送:
SEQ=1000 → 2000 → 3000 → 4000 → 5000
假设 SEQ=2000 丢失,接收方收到:
SEQ=1000 ✔ → [丢失] → 3000 ✔ → 4000 ✔ → 5000 ✔
但 接收方只能发送 ACK=2000(表示期望下一个字节),而不能告诉发送方 "3000, 4000, 5000 已经收到"。
发送方 只能重传 2000、3000、4000、5000,尽管 3000、4000、5000 已经正确到达,导致 浪费带宽。
SACK如何工作
如果要使用选择确认,在建立 TCP 连接时,要在 TCP 首部的选项中加上允许 SACK 选项,且双方必须事先商定好。
允许SACK 选项格式
如果使用选择确认,原来首部中的确认号的用法仍然不变(累积确认)。只是在 TCP 首部中都增加了 SACK 选项,以便报告收到的不连续的字节块的边界。
SACK格式
demo
TCP的流量控制
利用滑动窗口实现流量控制
流量控制 (flow control) :让发送方的发送速率不要太快,使接收方来得及接收。
利用滑动窗口机制可以很方便地在 TCP 连接上实现对发送方的流量控制。
利用可变窗口进行流量控制举例
可能发生死锁
持续计时器
持续计时器 (persistence timer):只要 TCP 连接的一方收到对方的零窗口通知,就启动该持续计时器。
若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),对方在确认这个探测报文段时给出当前窗口值。
若窗口仍然是零,收到这个报文段的一方就重新设置持续计时器。
若窗口不是零,则死锁的僵局就可以打破了。
TCP 的传输效率
控制TCP发送报文段的时机
TCP 维持一个变量,它等于最大报文段长度 MSS。只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去。
由发送方的应用进程指明要求发送报文段,即 TCP 支持的推送 (push) 操作。
发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去。
发送方糊涂窗口综合症
现象
- 发送方 TCP 每次接收到一字节的数据后就发送。
- 发送一个字节需要形成 41 字节长的 IP 数据报。效率很低。
解决方法
使用 Nagle 算法
Nagle 算法
算法简介
Nagle 算法是一种减少小数据包(小片段 TCP 包)传输的优化算法,由 John Nagle 提出,主要用于提高网络效率,减少网络拥塞。
它的核心思想是:
它的核心思想是:
- 发送端在未收到前一个小数据包的 ACK 确认 之前,不会发送新的小数据包,而是把多个小数据合并成一个大数据包后再发送。
- 这样可以减少大量的小数据包,提高网络传输效率。
工作原理
1.如果当前未确认的数据包(未收到 ACK),TCP 就会先缓存新数据,而不是立刻发送。
2.直到:
2.直到:
- 收到 ACK,或者
- 缓存数据累积足够大(等于 MSS,大约 1460 字节),才会发送新的数据包。
使用时机
1。低吞吐量的网络(如慢速 WAN)
1。低吞吐量的网络(如慢速 WAN)
- Nagle 算法减少数据包数量,降低网络开销,避免拥塞。
- 防止每次按键都触发一个 TCP 包,提高传输效率。
- 避免每个小请求都生成单独的 TCP 包,提高利用率。
关闭场景
Nagle 算法在某些情况下可能会导致延迟增加,特别是低延迟要求的应用,可以关闭它:
1.在线游戏(如 FPS、MOBA)
需要实时发送小数据包,不能等 ACK,否则会产生延迟。
2.VoIP(网络语音通话)、视频会议
语音数据包通常很小,如果等待合并会造成语音卡顿。
3.TCP_NODELAY 选项
许多应用(如游戏、金融交易系统)会手动关闭 Nagle 算法,使用 setsockopt(TCP_NODELAY) 让 TCP 立即发送数据。
1.在线游戏(如 FPS、MOBA)
需要实时发送小数据包,不能等 ACK,否则会产生延迟。
2.VoIP(网络语音通话)、视频会议
语音数据包通常很小,如果等待合并会造成语音卡顿。
3.TCP_NODELAY 选项
许多应用(如游戏、金融交易系统)会手动关闭 Nagle 算法,使用 setsockopt(TCP_NODELAY) 让 TCP 立即发送数据。
接收方糊涂窗口综合症
原因
接收方应用进程消耗数据太慢,例如:每次只读取一个字节。
解决方法
让接收方等待一段时间,使得或者接收缓存已有足够空间容纳一个最长的报文段,或者等到接收缓存已有一半空闲的空间。只要出现这两种情况之一,接收方就发出确认报文,并向发送方通知当前的窗口大小。
上述两种方法可配合使用,使得在发送方不发送很小的报文段的同时,接收方也不要在缓存刚刚有了一点小的空间就急忙把这个很小的窗口大小信息通知给发送方。
TCP的拥塞控制
拥塞控制的一般原理
拥塞
在某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降。这种现象称为拥塞 (congestion)。
最坏结果:系统崩溃
拥塞产生的原因
节点缓存容量太小;
链路容量不足;
处理机处理速率太慢;
拥塞本身会进一步加剧拥塞;
出现网络拥塞的条件
∑ 对资源需求 > 可用资源
增加资源能解决拥塞吗?不会
增大缓存,但未提高输出链路的容量和处理机的速度,排队等待时间将会大大增加,引起大量超时重传,解决不了网络拥塞
提高处理机处理的速率会将瓶颈转移到其他地方;
拥塞引起的重传并不会缓解网络的拥塞,反而会加剧网络的拥塞
拥塞控制与流量控制的区别
拥塞控制
防止过多的数据注入到网络中,避免网络中的路由器或链路过载。
是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。
流量控制
抑制发送端发送数据的速率,以使接收端来得及接收。
点对点通信量的控制,是个端到端的问题。
拥塞控制作用
拥塞控制的一般原理
- 拥塞控制的前提:网络能够承受现有的网络负荷。
- 实践证明,拥塞控制是很难设计的,因为它是一个动态问题。
- 分组的丢失是网络发生拥塞的征兆,而不是原因。
- 在许多情况下,甚至正是拥塞控制本身成为引起网络性能恶化、甚至发生死锁的原因。
TCP 的拥塞控制方法
开环控制和闭环控制
开环控制
在设计网络时,事先考虑周全,力求工作时不发生拥塞。
思路:力争避免发生拥塞。
但一旦整个系统运行起来,就不再中途进行改正了。
闭环控制
概念
基于反馈环路的概念。
根据网络当前运行状态采取相应控制措施。
思路:在发生拥塞后,采取措施进行控制,消除拥塞。
子主题
检测
监测网络系统,检测拥塞在何时、何处发生。
主要指标有:
- 由于缺少缓存空间而被丢弃的分组的百分数;
- 平均队列长度;
- 超时重传的分组数;
- 平均分组时延;
- 分组时延的标准差,等等。
- 这些指标的上升都标志着拥塞的增长
传送
将拥塞发生的信息传送到可采取行动的地方。
- 将拥塞发生的信息传送到产生分组的源站。
- 在路由器转发的分组中保留一个比特或字段,用该比特或字段的值表示网络没有拥塞或产生了拥塞。
- 周期性地发出探测分组等。
调整
调整网络系统的运行以解决出现的问题。
- 过于频繁,会使系统产生不稳定的振荡。
- 过于迟缓,不具有任何实用价值。
- 选择正确的时间常数是相当困难的。
几个缩写
MSS
- Maximum Segment Size
- 每个段最大的数据部分大小
- 在建立连接时确定
cwnd
- congettion window
- 拥塞窗口
rwnd
- receive window
- 接收窗口
swnd
- 发送窗口
- send window
- swnd=min(cwnd, rwnd)
拥塞控制方法
TCP 采用基于滑动窗口的方法进行拥塞控制,属于闭环控制方法。
TCP 发送方维持一个拥塞窗口 cwnd (Congestion Window)
拥塞窗口的大小取决于网络的拥塞程度,并且是动态变化的。
发送端利用拥塞窗口根据网络的拥塞情况调整发送的数据量。
发送窗口大小不仅取决于接收方窗口,还取决于网络的拥塞状况。
真正的发送窗口值 = Min (接收方通知的窗口值,拥塞窗口值)
控制拥塞窗口变化的原则
只要网络没有出现拥塞,拥塞窗口就可以再增大一些,以便把更多的分组发送出去,提高网络的利用率。
但只要网络出现拥塞或有可能出现拥塞,就必须把拥塞窗口减小一些,以减少注入到网络中的分组数,缓解网络出现的拥塞。
发送方判断拥塞的方法[隐式反馈]
超时重传计时器超时
网络已经出现了拥塞。
因传输出差错而丢弃分组的概率很小(远小于1 %)。
因此,发送方在超时重传计时器启动时,就判断网络出现了拥塞。
因此,发送方在超时重传计时器启动时,就判断网络出现了拥塞。
收到 3 个重复的确认
预示网络可能会出现拥塞。
TCP 拥塞控制算法
慢开始 (slow-start)
目的
探测网络的负载能力或拥塞程度。逐步探测可用带宽
工作方式
初始 cwnd 设为 1 MSS(最大报文段大小)
每收到一个 ACK,cwnd 指数增长(乘性增长):cwnd=cwnd×2
指数增长会持续,直到
发生丢包(网络出现拥塞)
cwnd 达到慢启动阈值 ssthresh(设定的临界值)
2 个控制变量
拥塞窗口 cwnd
- 初始值:2 种设置方法。
- 1 至 2 个最大报文段 MSS (旧标准)
- 2 至 4 个最大报文段 MSS(RFC 5681)
慢开始门限 ssthresh
防止拥塞窗口增长过大引起网络拥塞。
用法
当 cwnd < ssthresh 时,使用慢开始算法。
当 cwnd > ssthresh 时,停止使用慢开始算法,改用拥塞避免算法。
当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。
示例
总结
我们知道TCP为了保证效率,在建立连接后,不是一个包发送过去,再等对方一个确认再回来,而是多次发送对方接收窗口大小的数据,然后再给回一个确认包。
但是TCP为了能够拥塞控制,刚开始并不是直接一大堆包发送过去,而是使用一个包2个包4个包8个包。。。慢慢的去试探的,拥塞窗口也会慢慢的增大,也就是所谓的慢开始算法。
但是TCP为了能够拥塞控制,刚开始并不是直接一大堆包发送过去,而是使用一个包2个包4个包8个包。。。慢慢的去试探的,拥塞窗口也会慢慢的增大,也就是所谓的慢开始算法。
拥塞避免 (congestion avoidance)
目的:让拥塞窗口 cwnd 缓慢地增大,避免出现拥塞
拥塞窗口 cwnd 增大:每经过一个往返时间 RTT(不管在此期间收到了多少确认),发送方的拥塞窗口 cwnd = cwnd + 1。
具有加法增大 AI (Additive Increase) 特点:使拥塞窗口 cwnd 按线性规律缓慢增长。
注意:拥塞避免并非完全避免拥塞,而是让拥塞窗口增长得缓慢些,使网络不容易出现拥塞。
当网络出现拥塞时
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(重传定时器超时):
- ssthresh = max (cwnd/2,2)
- cwnd = 1
- 执行慢开始算法
目的
迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。
慢开始和拥塞避免算法的实现举例
1
2
3
4
5
6
7
8
9
10
快重传 (fast retransmit)
目的:避免等待超时重传,提前检测丢包,提高恢复速度.让发送方尽早知道发生了个别报文段的丢失。
工作方式
发送方只要连续收到三个重复的确认,就立即进行重传(即“快重传”),这样就不会出现超时。
使用快重传可以使整个网络的吞吐量提高约 20%。
快重传算法要求接收方立即发送确认,即使收到了失序的报文段,也要立即发出对已收到的报文段的重复确认。
注意:
快重传并非取消重传计时器,而是在某些情况下可以更早地(更快地)重传丢失的报文段。
快重传并非取消重传计时器,而是在某些情况下可以更早地(更快地)重传丢失的报文段。
示例
快恢复 (fast recovery)
目的
当发送端收到连续三个重复的确认时,不执行慢开始算法,而是执行快恢复算法 FR (Fast Recovery) 算法
工作方式
慢开始门限 ssthresh = 当前拥塞窗口 cwnd / 2
乘法减小 MD (Multiplicative Decrease) 拥塞窗口。
新拥塞窗口 cwnd = 慢开始门限 ssthresh
新拥塞窗口 cwnd = 慢开始门限 ssthresh
执行拥塞避免算法,使拥塞窗口缓慢地线性增大(加法增大 AI)
二者合在一起就是所谓的 AIMD 算法,使 TCP 性能有明显改进。
示例
主动队列管理 AQM
1.TCP 拥塞控制和网络层采取的策略有密切联系。
2.例如:
2.例如:
- 若路由器对某些分组的处理时间特别长,就可能引起发送方 TCP 超时,对这些报文段进行重传。
- 重传会使 TCP 连接的发送端认为在网络中发生了拥塞,但实际上网络并没有发生拥塞。
先进先出FIFO处理规则
尾部丢弃策略 (tail-drop policy):当队列已满时,以后到达的所有分组(如果能够继续排队,这些分组都将排在队列的尾部)将都被丢弃。
路由器的尾部丢弃往往会导致一连串分组的丢失,这就使发送方出现超时重传,使 TCP 进入拥塞控制的慢开始状态,结果使 TCP 连接的发送方突然把数据的发送速率降低到很小的数值
在最简单的情况下,路由器队列通常采用
先进先出 (FIFO) 处理规则与尾部丢弃策略 (tail-drop policy)。
当队列已满时,以后到达的所有分组将都被丢弃。
先进先出 (FIFO) 处理规则与尾部丢弃策略 (tail-drop policy)。
当队列已满时,以后到达的所有分组将都被丢弃。
分组丢弃使发送方出现超时重传,使 TCP 连接进入慢开始状态。
严重问题:全局同步.若路由器进行了尾部丢弃,
所有到达的分组都被丢弃,不论它们属于哪个 TCP 连接
所有到达的分组都被丢弃,不论它们属于哪个 TCP 连接
分组丢弃使发送方出现超时重传,使多个 TCP 连接同时进入慢开始状态,
发生全局同步 (global syncronization)。
发生全局同步 (global syncronization)。
主动队列管理 AQM
1998 年提出了主动队列管理 AQM (Active Queue Management)。
子主题
主动:不要等到路由器的队列长度已经达到最大值时才不得不丢弃后面到达的分组,而是在队列长度达到某个值得警惕的数值时(即当网络拥塞有了某些拥塞征兆时),就主动丢弃到达的分组。
AQM 可以有不同实现方法,其中曾流行多年的就是随机早期检测 RED (Random Early Detection)。
随机早期检测 RED
路由器队列维持两个参数:
- 队列长度最小门限 THmin
- 队列长度最大门限 THmax 。
RED 对每一个到达的分组都先计算平均队列长度 LAV 。
- 若平均队列长度小于最小门限 THmin,则将新到达的分组放入队列进行排队。
- 若平均队列长度超过最大门限 THmax ,则将新到达的分组丢弃。
- 若平均队列长度介于在最小门限 THmin 和最大门限 THax 之间,则按照某一概率 p 将新到达的分组丢弃。
RED 路由器到达队列维持两个参数:Thmin, Thmax,分成为三个区域:
当 LAV < Thmin 时,丢弃概率 p = 0。
当 LAV > Thmax 时,丢弃概率 p = 1。
当 Thmin ≤ LAV ≤ Thmax时,丢弃概率 p: 0 < p < 1 。
当 LAV > Thmax 时,丢弃概率 p = 1。
当 Thmin ≤ LAV ≤ Thmax时,丢弃概率 p: 0 < p < 1 。
- 多年的实践证明,RED 的使用效果并不太理想。
- 2015 年公布的 RFC 7567 已经把 RFC 2309 列为“陈旧的”,并且不再推荐使用 RED。
- 但对路由器进行主动队列管理 AQM 仍是必要的。
- AQM 实际上就是对路由器中的分组排队进行智能管理,而不是简单地把队列的尾部丢弃。
- 现在已经有几种不同的算法来代替旧的 RED,但都还在实验阶段。
TCP的运输连接管理
TCP 的连接建立
运输连接的三个阶段
TCP 是面向连接的协议。
TCP 连接有三个阶段
连接建立
数据传送
连接释放
TCP 的连接管理就是使 TCP 连接的建立和释放都能正常地进行。
TCP 连接建立过程中要解决的三个问题
要使每一方能够确知对方的存在。
要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)。
能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。
Client / Server
TCP 连接的建立采用客户服务器方式。
主动发起连接建立的应用进程叫做客户 (client)。
被动等待连接建立的应用进程叫做服务器 (server)。
三次握手
TCP 的连接释放
四次挥手
必须等待 2MSL 的时间的原因
第一,保证发送的最后一个 ACK 报文段能够到达 B。
第二,防止“已失效的连接请求报文段”出现在本连接中。
保活计时器
- 用来防止在 TCP 连接出现长时期空闲。
- 通常设置为 2 小时 。
- 若服务器过了 2 小时还没有收到客户的信息,它就发送探测报文段。
- 若发送了 10 个探测报文段(每一个相隔 75 秒)还没有响应,就假定客户出了故障,因而就终止该连接。
TCP 的有限状态机
常见问题
如果有个包重传N次还是失败那么会一直重传到成功吗?
- 不会,一般都是重传几次,还是失败后就不会重传了,这一般都取决于操作系统的设定!
- 比如有些操作系统重传5次还没有收到确认包后,那么就不会再重传这个包了!
- 一般重传N次还是没有收到确认,那么就会发送一个报文首部字段中RST为1,表示这个包传输失败,即会断开TCP连接!
TIME-WAIT 状态为什么需要等待 2MSL?
TCP 的 TIME-WAIT 状态需要等待 2 倍的最大报文段生存时间(2MSL, Maximum Segment Lifetime),主要是为了确保 可靠连接终止 并 防止旧报文干扰新连接。具体来说,有以下两个核心原因:
1. 确保对方正确接收最后的 ACK
在 TCP 连接的四次挥手 过程中,主动关闭连接的一方(通常是客户端)会发送最后的 ACK,确认接收到对方的 FIN,然后进入 TIME-WAIT 状态。
🔹 问题:如果最后的 ACK 丢失了怎么办?
🔹 解决方案:等待 2MSL,确保对方有足够时间重发 FIN
如果最后的 ACK 在传输过程中丢失,被动关闭方(通常是服务器)会超时并 重发 FIN。如果主动关闭方 立即释放连接,它就无法再接收这个重发的 FIN,导致对方迟迟等不到 ACK,无法正常关闭。
通过 TIME-WAIT 等待 2MSL,可以 确保任何可能丢失的 FIN 都能被正确接收并重新发送 ACK,保证连接完全关闭。
所以客户端发送 ACK 后需要留出 2MSL 时间(ACK 到达服务器 + 服务器发送 FIN 重传包,一来一回)等待确认服务器端确实收到了 ACK 包。
在 TCP 连接的四次挥手 过程中,主动关闭连接的一方(通常是客户端)会发送最后的 ACK,确认接收到对方的 FIN,然后进入 TIME-WAIT 状态。
🔹 问题:如果最后的 ACK 丢失了怎么办?
🔹 解决方案:等待 2MSL,确保对方有足够时间重发 FIN
如果最后的 ACK 在传输过程中丢失,被动关闭方(通常是服务器)会超时并 重发 FIN。如果主动关闭方 立即释放连接,它就无法再接收这个重发的 FIN,导致对方迟迟等不到 ACK,无法正常关闭。
通过 TIME-WAIT 等待 2MSL,可以 确保任何可能丢失的 FIN 都能被正确接收并重新发送 ACK,保证连接完全关闭。
所以客户端发送 ACK 后需要留出 2MSL 时间(ACK 到达服务器 + 服务器发送 FIN 重传包,一来一回)等待确认服务器端确实收到了 ACK 包。
2. 防止旧连接的残余报文干扰新连接
🔹 问题:如果同一 IP 和端口号对(Socket 对)很快复用,旧报文可能会被误认为是新连接的数据
🔹 解决方案:等待 2MSL,确保旧数据包在网络中完全消失
TCP 采用 四元组(源 IP、源端口、目标 IP、目标端口) 作为连接标识。如果一个 TCP 连接关闭后,立刻重新建立一个相同的连接(相同四元组),可能会遇到以下问题:
1) .旧的 TCP 报文在网络中滞留
🔹 问题:如果同一 IP 和端口号对(Socket 对)很快复用,旧报文可能会被误认为是新连接的数据
🔹 解决方案:等待 2MSL,确保旧数据包在网络中完全消失
TCP 采用 四元组(源 IP、源端口、目标 IP、目标端口) 作为连接标识。如果一个 TCP 连接关闭后,立刻重新建立一个相同的连接(相同四元组),可能会遇到以下问题:
1) .旧的 TCP 报文在网络中滞留
- 网络中的某些数据包可能因为路由器排队、重传等原因 延迟到达。
- 如果旧的 TCP 报文在新连接建立后才到达,TCP 可能会 误认为是新连接的数据,导致数据错乱。
- 2MSL 等待确保 所有旧连接的数据包已经从网络中清除。
- 这样,新的连接就不会受到老数据包的影响,避免数据混淆问题。
为什么是 2MSL,而不是 1MSL?
MSL(Maximum Segment Lifetime) 是 TCP 报文在网络中的最大存活时间,通常设定为 30s 或 60s。TCP 选择 2MSL 而不是 1MSL,是因为:
1)FIN 和 ACK 都可能丢失
MSL(Maximum Segment Lifetime) 是 TCP 报文在网络中的最大存活时间,通常设定为 30s 或 60s。TCP 选择 2MSL 而不是 1MSL,是因为:
1)FIN 和 ACK 都可能丢失
- 假设最后的 ACK 丢失,对方会重发 FIN,等待 1MSL 后可能仍未收到 ACK。
- 通过等待 2MSL,确保对方有足够时间发送 FIN 并收到 ACK。
- 1MSL 仅保证 一个方向的旧报文消失,但 TCP 连接是双向的,必须确保双向的所有旧数据包完全清除。
- 2MSL 既覆盖了主动方的最后一个 ACK,也覆盖了被动方可能的 FIN 重传,彻底清理旧连接的残留数据。
三次握手可以携带数据吗?
第一次、第二次握手不可以携带数据,而第三次握手是可以携带数据的。
我们可以思考一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据,疯狂着重复发 SYN 报文,这会让服务器花费大量的内存空间来缓存这些报文,这样服务器就更容易被攻击了。
对于第三次握手,此时客户端已经处于连接状态,他已经知道服务器的接收、发送能力是正常的了,所以可以携带数据是情理之中。
我们可以思考一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据,疯狂着重复发 SYN 报文,这会让服务器花费大量的内存空间来缓存这些报文,这样服务器就更容易被攻击了。
对于第三次握手,此时客户端已经处于连接状态,他已经知道服务器的接收、发送能力是正常的了,所以可以携带数据是情理之中。
TCP和UDP可以同时绑定同一个端口吗?
可以,TCP和UDP是两种不同的传输层协议,它们各自使用的端口号也相互独立,如TCP有一个80端口,UDP也可以有一个80端口,二者并不冲突。
IP层已经有了分片机制,TCP为什么还需要分段?
因为IP层本身没有超时重传机制,超时和重传是由TCP负责的,当某一个IP分片丢失后,TCP就得重传整个IP报文的所有分片,效率太低。所以一般都是UDP使用IP分片,TCP使用分段而不使用分片。TCP在建立连接时,会根据网卡MTU的大小协商双方的MSS值,超过MSS时,就会先进行分段,由它形成的IP包的长度也就不会大于MTU ,也就不用进行IP分片了。
MTU 与 IP 分片问题
什么是 MTU(Maximum Transmission Unit,最大传输单元)?
MTU 指的是网络层(IP 层)一次能传输的最大数据包大小。
常见 MTU 值:
常见 MTU 值:
- 以太网(Ethernet):1500 字节
- PPPoE(拨号):1492 字节
- 某些 VPN:1400 字节
- IPv6 默认 MTU:1280 字节
为什么 IP 分片不可预测?
IP 层(网络层)为了适应不同 MTU,可能会对数据包进行“分片”,导致以下问题:
- 路径 MTU 可能变化
- 分片可能会丢失
- 不同网络 MTU 不同,可能造成不必要的分片
为什么 TCP 分段能避免 IP 分片?
TCP 在传输层采用 MSS(最大报文段大小)进行数据分段,能确保报文适应不同 MTU,避免 IP 分片带来的问题。
什么是 MSS?
TCP 可以动态调整分段大小,比如 使用 Path MTU Discovery(PMTUD) 发现路径 MTU,调整 MSS。
不同链路 MTU 可能不同,但 TCP 只需保证 MSS 不超过路径 MTU,避免 IP 分片问题
如果客户端没有收到服务端返回的FIN包,客户端会一直等待吗?
并不会,因为如果没有收到服务器端的FIN包,会让客户端一直处于FIN_WAIT2状态,FIN_WAIT2没有时间限制,如果本端进入FIN_WAIT2如果,对端失去响应,本端也不会一直卡在FIN_WAIT2状态,因为还可以使用TCP keepalive计时器避免此问题。
0 条评论
下一页