一、TIME_WAIT和CLOSE_WAIT
1. TIME_WAIT 状态
1.1 什么是 TIME_WAIT?
-
定义 :
TIME_WAIT
是 TCP 连接关闭时的一个状态,出现在主动关闭连接的一方(即先发送FIN
包的一方)。 -
触发条件 :在 TCP 四次挥手的最后阶段,主动关闭方在收到对方的
ACK
后,会进入TIME_WAIT
状态。 -
持续时间 :
2 * MSL
(Maximum Segment Lifetime,报文最大生存时间),默认约 60 秒(Linux)。
1.2 为什么需要 TIME_WAIT?
-
确保最后的 ACK 可靠到达 :如果最后的
ACK
丢失,对方会重发FIN
,此时处于TIME_WAIT
的一方可以重新发送ACK
。 -
防止旧报文干扰新连接 :旧连接的延迟报文可能被误认为属于新连接(例如相同四元组的连接)。
TIME_WAIT
会等待足够时间让网络中残留的旧报文消失。
1.3 TIME_WAIT 导致 bind 失败的原因
-
问题场景 :在高并发短连接的服务端(如 HTTP 短连接),主动关闭方(服务端)会积累大量
TIME_WAIT
状态的连接。 -
资源耗尽 :每个
TIME_WAIT
连接会占用一个本地端口。当可用端口耗尽时,新连接无法绑定端口,导致bind()
失败(错误:Address already in use
)。
1.4 解决方法
-
(1) 允许端口重用
修改内核参数,允许
TIME_WAIT
端口被新连接复用:bash# 修改 /etc/sysctl.conf net.ipv4.tcp_tw_reuse = 1 # 允许复用 TIME_WAIT 端口(仅对客户端有效) net.ipv4.tcp_tw_recycle = 0 # 谨慎使用,可能影响 NAT 环境
-
(2) 调整 TIME_WAIT 超时时间
缩短
TIME_WAIT
的持续时间(默认 60 秒):bashnet.ipv4.tcp_fin_timeout = 30 # 缩短到 30 秒
-
(3) 增加端口范围
扩大本地端口池范围:
bashnet.ipv4.ip_local_port_range = 10000 65000
-
(4) 服务端避免主动关闭连接
如果是服务端,尽量让客户端主动关闭连接(例如 HTTP 协议中,服务端设置
Connection: close
后由客户端关闭)。
2. CLOSE_WAIT 状态
2.1 什么是 CLOSE_WAIT?
-
定义 :
CLOSE_WAIT
是被动关闭连接的一方(即收到FIN
包的一方)所处的状态。 -
触发条件 :当对方发送
FIN
包关闭连接时,本地会进入CLOSE_WAIT
状态,等待应用程序处理完数据后发送FIN
包。
2.2 为什么会出现大量 CLOSE_WAIT?
-
根本原因 :应用程序未正确关闭连接。
例如:服务端收到客户端的
FIN
后,进入CLOSE_WAIT
状态,但代码未调用close()
或shutdown()
发送FIN
。 -
风险 :大量
CLOSE_WAIT
连接会占用文件描述符,导致资源泄漏。
2.3 解决方法
-
(1) 检查代码逻辑
确保所有连接在使用完毕后正确关闭:
python# 示例代码(Python) try: conn, addr = server_socket.accept() # 处理数据... finally: conn.close() # 必须显式关闭!
-
(2) 设置超时机制
为连接设置超时,避免长时间卡在
CLOSE_WAIT
:bash# 内核参数(全局) net.ipv4.tcp_keepalive_time = 600 # 600 秒无活动后发送探测包
3. 总结
状态 | 角色 | 原因 | 解决方法 |
---|---|---|---|
TIME_WAIT | 主动关闭方 | 确保连接彻底关闭 | 端口复用、调整内核参数 |
CLOSE_WAIT | 被动关闭方 | 应用程序未关闭连接 | 检查代码、显式调用 close() |
关键点:
-
TIME_WAIT
是协议设计的保护机制,不要试图完全消除它,而是优化其影响。 -
CLOSE_WAIT
是程序 BUG,必须通过代码修复!
二、TCP 滑动窗口和流量控制
- 1.基本概念
- TCP 滑动窗口是 TCP 协议用于实现流量控制和提高传输效率的一种机制。它允许发送方在收到接收方的确认之前,连续发送多个数据段,而不必每发送一个数据段就等待确认。窗口的大小表示发送方可以在未收到确认的情况下发送的数据量。
- 2.工作原理
- 窗口大小的确定:发送方和接收方在建立 TCP 连接时,会在双方的 TCP 报头中协商窗口大小。这个窗口大小会根据网络状况和接收方的处理能力等因素动态调整。
- 数据发送与滑动:发送方在发送数据时,会维护一个发送窗口。窗口内的数据是可以被发送方发送出去的数据。当发送方发送了窗口内的数据后,只要没有收到接收方的确认,就不能再发送超过窗口大小的数据。当发送方收到接收方对窗口内某部分数据的确认后,窗口会向前滑动,允许发送方发送更多的数据。
- 举例说明:假设发送方的窗口大小为 3,初始时窗口内包含序号为 1、2、3 的数据段。发送方发送这三个数据段后,窗口就不能再滑动,直到收到接收方的确认。如果接收方成功收到了序号为 1 的数据段并发送了确认,那么发送方的窗口就会向前滑动一个位置,此时窗口内包含序号为 2、3、4 的数据段,发送方就可以发送序号为 4 的数据段了。
TCP 流量控制
- 1.基本概念
- 流量控制是 TCP 协议为了防止发送方发送数据过快,导致接收方无法及时处理而产生数据丢失或拥塞的一种机制。它通过让接收方控制发送方的发送速度来实现。
- 2.实现方式
- 利用滑动窗口实现:接收方通过在 TCP 报头中的窗口字段,告诉发送方自己当前能够接收的数据量,即接收窗口大小。发送方根据接收方反馈的接收窗口大小来调整自己的发送窗口大小,从而控制发送数据的速度。
- 动态调整窗口大小:接收方会根据自己的缓存空间和处理能力动态调整接收窗口的大小。当接收方的缓存空间快满时,它会减小接收窗口大小,通知发送方减慢发送速度;当接收方处理完一些数据,缓存空间有空闲时,它会增大接收窗口大小,允许发送方发送更多的数据。
- 举例说明:如果接收方的缓存空间为 1000 字节,当前已经接收了 500 字节的数据还未处理,那么它会将接收窗口大小设置为 500 字节,并在发送给发送方的确认报文中告知发送方。发送方收到这个确认报文后,就会将自己的发送窗口大小调整为 500 字节,只发送 500 字节的数据,直到收到接收方新的确认报文和窗口大小信息。
滑动窗口与流量控制的关系
- 滑动窗口是实现流量控制的具体手段,而流量控制是滑动窗口机制的主要目的之一。通过滑动窗口的动态调整,TCP 协议能够实现高效、可靠的数据传输,同时避免网络拥塞和数据丢失,确保数据传输的稳定性和效率。
滑动窗口
基本概念

在《图解 TCP/IP》中提到,TCP 滑动窗口是一种流量控制机制,允许发送方在未收到接收方确认时,连续发送多个数据段,以此提高数据传输效率。滑动窗口就像一个可以在数据序列上滑动的窗口,窗口内的数据是可以被发送的。

窗口的构成与工作机制

- 窗口大小:窗口大小代表了发送方在未收到确认的情况下能够发送的数据量。它由接收方告知发送方,通过 TCP 报头中的 "窗口大小" 字段来传递。例如,接收方告知发送方窗口大小为 500 字节,那么发送方最多可以连续发送 500 字节的数据而无需等待确认。
- 窗口滑动:当发送方发送了窗口内的数据后,若收到接收方对部分数据的确认,窗口就会向前滑动,允许发送方继续发送后续的数据。比如,发送方窗口内包含序号为 1 - 500 的字节数据,发送完后收到接收方对序号 1 - 100 字节数据的确认,此时窗口就会向前滑动 100 个字节,变为包含序号 101 - 600 的字节数据,发送方可以接着发送这部分数据。
图解tcp/ip示例理解
书中通常会用形象的图示来展示滑动窗口的工作过程。假设发送方和接收方建立连接后,接收方通告窗口大小为 4 个数据段。发送方依次发送数据段 1、2、3、4,在未收到确认前,窗口停留在这 4 个数据段上。当收到接收方对数据段 1 的确认后,窗口向前滑动一个位置,发送方可以发送数据段 5。
TCP 流量控制
基本原理
TCP 流量控制的核心目标是防止发送方发送数据过快,导致接收方因处理不及而出现数据丢失。《图解 TCP/IP》强调,这主要通过接收方动态调整窗口大小来实现。接收方会根据自身的缓存空间和处理能力,在 TCP 报头中告知发送方当前能够接收的数据量。
动态调整窗口大小
- 窗口减小:当接收方的缓存空间接近满时,它会减小通告给发送方的窗口大小。例如,接收方原本通告窗口大小为 1000 字节,随着缓存逐渐被填满,它将窗口大小减小到 200 字节,发送方收到这个信息后,就会相应地减少发送数据的量。
- 窗口增大:当接收方处理完部分数据,缓存空间有空闲时,会增大窗口大小。比如接收方处理完 500 字节的数据后,将窗口大小从 200 字节增大到 700 字节,发送方就可以发送更多的数据。


结合滑动窗口实现流量控制

滑动窗口是实现流量控制的具体手段。发送方根据接收方通告的窗口大小来调整自己的发送窗口,从而控制发送数据的速度。例如,接收方通告窗口大小为 300 字节,发送方的发送窗口就限制在 300 字节以内,只能发送这个范围内的数据。当接收方的窗口大小发生变化时,发送方的发送窗口也会相应调整,确保数据的发送速度与接收方的处理能力相匹配。
滑动窗口和流量控制的意义

《图解 TCP/IP》指出,滑动窗口和流量控制机制使得 TCP 能够在不同性能的设备和网络环境下实现高效、可靠的数据传输。通过动态调整窗口大小,避免了数据的堆积和丢失,提高了网络资源的利用率,保证了通信的稳定性和效率。
ctp总结
1. TCP 基础概念
协议定义与作用
TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议。它主要负责在应用程序之间提供可靠的数据传输服务,确保数据在传输过程中不丢失、不重复且按序到达。
与 UDP 的对比
- 连接性:TCP 是面向连接的,通信前需要建立连接;UDP 是无连接的,无需建立连接即可发送数据。
- 可靠性:TCP 提供可靠传输,通过确认机制、重传机制等保证数据准确到达;UDP 不保证可靠性,数据可能丢失、重复或乱序。
- 传输效率:由于 TCP 需要建立连接、维护状态和进行错误处理,其传输效率相对较低;UDP 开销小,传输效率高。
- 应用场景:TCP 适用于对数据准确性要求高的场景,如文件传输、网页浏览等;UDP 适用于对实时性要求高、对少量数据丢失不太敏感的场景,如视频流、音频流等。
2. TCP 报文格式

源端口和目的端口
- 各占 16 位,用于标识发送方和接收方的应用程序。源端口是发送方应用程序使用的端口,目的端口是接收方应用程序监听的端口。
序号
- 占 32 位,用于标识 TCP 发送的字节流中每个字节的编号。发送方在发送数据时,会为每个字节分配一个序号,接收方可以根据序号对数据进行排序和确认。
确认号
- 占 32 位,是期望收到对方下一个报文段的第一个数据字节的序号。表示接收方已经正确收到了该序号之前的数据,希望接下来收到该序号对应的数据。
首部长度
- 占 4 位,指示 TCP 首部的长度,单位是 32 位字(即 4 字节)。由于 TCP 首部可能包含可选字段,首部长度不固定,通过该字段可以确定首部的实际长度。
保留位
- 占 6 位,目前保留未用,为未来的扩展预留。
控制位
- 包括 URG(紧急指针有效)、ACK(确认号有效)、PSH(推送数据)、RST(重置连接)、SYN(同步序号,用于建立连接)、FIN(终止连接)等标志位,用于控制 TCP 连接的建立、数据传输和关闭等操作。
窗口大小
- 占 16 位,用于流量控制,指示接收方当前的接收窗口大小,即接收方允许发送方发送的数据量。
校验和
- 占 16 位,用于检验 TCP 报文段在传输过程中是否发生错误。发送方计算校验和并填充到该字段,接收方重新计算校验和并与接收到的校验和进行比较,若不一致则认为报文段有错误。
紧急指针
- 占 16 位,只有当 URG 标志位为 1 时有效,指示紧急数据在报文段中的位置。
3. TCP 连接建立与关闭

三次握手(建立连接)
- 客户端向服务器发送 SYN 包:客户端向服务器发送一个 TCP 报文段,其中 SYN 标志位设置为 1,同时选择一个初始序号(ISN),表示客户端希望建立连接。
- 服务器回应 SYN + ACK 包:服务器收到客户端的 SYN 包后,向客户端发送一个包含 SYN 和 ACK 标志位都为 1 的报文段。SYN 表示服务器同意建立连接,并选择自己的初始序号;ACK 表示对客户端 SYN 包的确认,确认号为客户端的初始序号加 1。
- 客户端发送 ACK 包:客户端收到服务器的 SYN + ACK 包后,向服务器发送一个 ACK 标志位为 1 的报文段,确认号为服务器的初始序号加 1,表示客户端确认连接建立。
四次挥手(关闭连接)
- 客户端发送 FIN 包:客户端完成数据发送后,向服务器发送一个 FIN 标志位为 1 的报文段,表示客户端不再发送数据,请求关闭连接。
- 服务器回应 ACK 包:服务器收到客户端的 FIN 包后,向客户端发送一个 ACK 标志位为 1 的报文段,确认号为客户端的序号加 1,表示服务器已经收到客户端的关闭请求。
- 服务器发送 FIN 包:服务器完成数据发送后,向客户端发送一个 FIN 标志位为 1 的报文段,表示服务器也不再发送数据,请求关闭连接。
- 客户端回应 ACK 包:客户端收到服务器的 FIN 包后,向服务器发送一个 ACK 标志位为 1 的报文段,确认号为服务器的序号加 1,表示客户端已经收到服务器的关闭请求,连接正式关闭。

4. TCP 可靠传输机制
确认机制


- 接收方收到数据后,会向发送方发送确认报文,确认号表示期望收到的下一个字节的序号。发送方根据确认号来判断哪些数据已经被正确接收。
重传机制


- 超时重传:发送方发送数据后,会启动一个定时器。如果在定时器超时之前没有收到接收方的确认,发送方会重新发送该数据。
- 快速重传:当发送方连续收到 3 个重复的确认时,认为有一个数据段丢失,立即重传该数据段,而不必等待超时。
滑动窗口机制
- 发送方和接收方分别维护一个发送窗口和接收窗口。发送窗口表示发送方在未收到确认的情况下可以发送的数据范围,接收窗口表示接收方能够接收的数据范围。通过窗口的滑动,实现高效的数据传输和流量控制。
5. TCP 流量控制

基本原理
- 流量控制是为了防止发送方发送数据过快,导致接收方无法及时处理而产生数据丢失。接收方通过在 TCP 报头中的窗口字段告知发送方自己当前的接收窗口大小,发送方根据该窗口大小调整自己的发送速度。
动态调整(滑动窗口)



- 接收方会根据自身的缓存空间和处理能力动态调整接收窗口大小。当缓存空间快满时,减小窗口通知发送方减慢速度;当处理完数据,缓存有空闲时,增大窗口允许发送更多数据。
6. TCP 拥塞控制
拥塞概念
- 拥塞是指网络中出现过多的数据,导致网络性能下降,如延迟增加、吞吐量降低等。
主要算法
- 慢开始:初始时发送方拥塞窗口(cwnd)设为较小值(通常为 1 个 MSS,最大段大小),每收到一个确认,cwnd 就增加 1 个 MSS。当 cwnd 达到慢开始门限(ssthresh)时,进入拥塞避免阶段。
- 拥塞避免:每经过一个往返时延(RTT),cwnd 只增加 1 个 MSS,使拥塞窗口缓慢增长。
- 快重传:当发送方连续收到 3 个重复确认时,认为有一个数据段丢失,立即重传该数据段,而不必等待超时重传。
- 快恢复:执行快重传后,将 ssthresh 减半,cwnd 设为 ssthresh,然后进入拥塞避免阶段。
7. TCP 其他特性
延迟应答

- 接收方收到数据后,不立即发送确认,而是等待一段时间。这样做可以在等待期间,如果有更多的数据到达,在一个确认中确认更多的数据,提高传输效率。但有时间和数据量的限制。
捎带应答

- 当接收方有数据要发送给发送方时,将对之前收到数据的确认信息放在自己要发送的数据的 TCP 报头中,一起发送给发送方,减少网络中的报文数量。
面向字节流
- TCP 将应用层交付的数据看作无结构的字节流进行传输,发送方将数据拆分成多个 TCP 报文段发送,接收方将接收到的报文段重新组装成完整的字节流交付给应用层。
8. TCP 异常处理
客户端异常关闭
- 客户端突然断电、崩溃等异常关闭,没有正常发送 FIN 包。服务器继续发送数据,一段时间后未收到确认,会触发超时重传。多次重传失败后,服务器会关闭连接。
服务器异常关闭
- 服务器异常关闭,客户端可能还在发送数据。客户端发送的数据得不到确认,触发超时重传。若服务器一直未响应,客户端最终会关闭连接。
网络中断
- 在数据传输过程中,网络突然中断。发送方和接收方都无法收到对方的报文。发送方会不断重传数据,当重传次数达到上限或超时时间过长,会关闭连接。网络恢复后,若双方都未关闭连接,可继续正常通信。
