一、TCP三次握手

img

二、TCP四次挥手

img

time_wait状态如何产生? 首先调用close()发起主动关闭的一方,在发送最后一个ACK之后会进入time_wait的状态,也就说该发送方会保持2MSL时间之后才会回到初始状态。MSL值得是数据包在网络中的最大生存时间。产生这种结果使得这个TCP连接在2MSL连接等待期间,定义这个连接的四元组(客户端IP地址和端口,服务端IP地址和端口号)不能被使用。

2.time_wait状态产生的原因

1)为实现TCP全双工连接的可靠释放

由TCP状态变迁图可知,假设发起主动关闭的一方(client)最后发送的ACK在网络中丢失,由于TCP协议的重传机制,执行被动关闭的一方(server)将会重发其FIN,在该FIN到达client之前,client必须维护这条连接状态,也就说这条TCP连接所对应的资源(client方的local_ip,local_port)不能被立即释放或重新分配,直到另一方重发的FIN达到之后,client重发ACK后,经过2MSL时间周期没有再收到另一方的FIN之后,该TCP连接才能恢复初始的CLOSED状态。如果主动关闭一方不维护这样一个TIME_WAIT状态,那么当被动关闭一方重发的FIN到达时,主动关闭一方的TCP传输层会用RST包响应对方,这会被对方认为是有错误发生,然而这事实上只是正常的关闭连接过程,并非异常。

2)为使旧的数据包在网络因过期而消失

为说明这个问题,我们先假设TCP协议中不存在TIME_WAIT状态的限制,再假设当前有一条TCP连接:(local_ip, local_port, remote_ip,remote_port),因某些原因,我们先关闭,接着很快以相同的四元组建立一条新连接。本文前面介绍过,TCP连接由四元组唯一标识,因此,在我们假设的情况中,TCP协议栈是无法区分前后两条TCP连接的不同的,在它看来,这根本就是同一条连接,中间先释放再建立的过程对其来说是“感知”不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的数据到达remote peer后,会被该remot peer的TCP传输层当做当前TCP连接的正常数据接收并向上传递至应用层(而事实上,在我们假设的场景下,这些旧数据到达remote peer前,旧连接已断开且一条由相同四元组构成的新TCP连接已建立,因此,这些旧数据是不应该被向上传递至应用层的),从而引起数据错乱进而导致各种无法预知的诡异现象。作为一种可靠的传输协议,TCP必须在协议层面考虑并避免这种情况的发生,这正是TIME_WAIT状态存在的第2个原因。

系统/协议栈 默认 TIME_WAIT持续时间 (2MSL) MSL 默认值 是否可配置 关键配置参数/方法
标准 Linux 系统 60秒 30秒 内核参数(如 net.ipv4.tcp_fin_timeout
LWIP 120秒 60秒 修改 LWIP_TCP_MAX_MSLTCP_MSL宏定义
CH395 依赖于底层TCP实现 依赖于底层TCP实现 通常可以 查阅芯片数据手册或SDK中的配置选项

解决办法:

方法一:源端口采用自动分配。SockInf.SourPort = 0; // 源端口设为0,启用自动分配

方法二:源端口采用端口复用,忽略TIME_WAIT时间

三、TCP理论上是4次挥手,但是为什么捉取报文只有3次挥手?

当被动关闭方(服务器)在收到FIN报文后,如果没有数据要发送开启了TCP延迟确认机制,那么第二次挥手的ACK和第三次挥手的FIN就会合并成一个报文发送,这样就出现了三次挥手。

四、插拔网线在几秒内完成,TCP为什么不需要重新连接,而是可以直接通信?

TCP连接的本质是通信双方在本地内存中维护的TCP状态机。当网线被拔掉时,操作系统并不会立即改变TCP连接的状态信息,连接仍然保持在ESTABLISHED状态。只有在以下几种情况下,连接才会真正断开:

  1. 有数据传输时的场景

如果服务端在网线拔掉期间发送了数据报文,会触发TCP的超时重传机制。在Linux系统中,这个机制由tcp_retries2参数控制(默认值15),但实际重传超时时间是指数增长的:第一次2秒,第二次4秒,第三次8秒,以此类推。如果在服务端重传次数达到最大值之前,客户端插回网线,服务端发送的数据包会被正常接收并确认,连接就能继续正常工作,就像什么都没发生过一样。

  1. 无数据传输时的场景

如果双方都没有开启TCP keepalive机制,即使网线被拔掉,TCP连接状态也会一直保持存在。这是因为没有数据交互,TCP协议无法感知到对方是否存活。当连接空闲时间超过tcp_keepalive_time(默认7200秒,即2小时)后,系统会开始发送探测包。如果连续发送tcp_keepalive_probes次(默认9次)探测包且未收到响应,系统会认为连接已断开并关闭连接。总探测时间约为2小时11分15秒。如果在探测期间插回网线,连接可以恢复正常。

五、客户端一直重传SYN包

客户端一直重传SYN包,通常是因为TCP三次握手失败导致的。当客户端发送SYN包后,如果在超时时间内没有收到服务器的SYN+ACK响应,就会触发重传机制。

问题现象:移植完协议后,可以正常连接并传输数据,然后下周来进行调试的时候,发现一直连接不上服务器A,后面更改其他的服务器可以连接成功,或者使用其他的客户端连接服务器A也可以正常连接,后面发现原因服务器不接受1031端口的连接,更改端口之后可以连接成功,所以为避免TIME_WAIT时间,最好使用自由分配的端口连接。

六、客户端连接过程中客户端突然发送FIN包

客户端连续调用多次连接函数,导致异常中断

当你第一次调用 InitSocketParam()CH395SocketInitOpen()时,CH395会完成Socket的初始化并将其置于可用的初始状态。随后,你的程序通过 CH395TCPConnect()(客户端)或 CH395TCPListen()(服务器)等命令,驱动Socket进入连接建立或监听状态,最终进入稳定的数据传输状态。

如果在连接成功并开始通信后再次调用初始化函数,相当于强行将Socket的状态重置回初始状态。这会直接导致已有的TCP连接被意外终止,具体表现如下:

  1. 连接断开:最直接的后果是当前的TCP连接会断开。对端的设备或服务器会检测到连接已中断。

  2. 数据丢失:在重置过程中,芯片内部与该Socket相关的发送和接收缓冲区很可能被清空,导致尚未送达的数据或已接收但尚未被主控MCU读取的数据丢失。

  3. 端口占用与冲突:即使Socket被重置,操作系统或网络协议栈可能仍会认为之前的连接处于TIME_WAIT状态。此时若立即用相同的端口尝试建立新连接,可能会遇到“端口被占用”或“地址已使用”的错误。

  4. 程序逻辑混乱:你的程序需要维护Socket的状态。重复初始化会使你的程序状态与CH395芯片的实际状态不一致,从而引发难以调试的逻辑错误。

七、客户端连接过程中服务器突然发送FIN包

原因,服务器短时间收到同一个ip的连接请求会判定成恶意攻击

解决办法,在连接断开或者网卡状态变化后等待一定时间在进行重连机制

八、异常报文

#6: [TCP ACKed unseen segment] 1883 → 1031 [ACK]

  • 含义:服务器(112.81.83.26,端口 1883)向客户端(192.168.10.191,端口 1031)发送了一个TCP确认包。

  • 关键在于其“ACK”值:它确认的序列号是 Ack=369

  • 异常点:这个确认号 369意味着服务器认为它已经收到了客户端发送的、序列号直到369的数据。然而,在抓包记录中,我们只看到了客户端发送的第一个SYN包(Seq=0),并没有看到客户端发送过任何携带369字节数据的包。因此,Wireshark提示 ACKed unseen segment(确认了未见过的数据段)。

解读:这表明在抓包开始前,客户端和服务器之间可能已经有过一次连接或数据交互,然后服务器认为连接没有断开,但是客户端认为连接已经断开,需要重连服务器,导致客户端开始新的连接,但是服务器保持上一次的连接。

#7: 1031 → 1883 [RST, ACK]

  • 含义:客户端立即向服务器回复了一个 RST(复位)包

  • 这是关键响应:客户端收到了一个它无法理解的ACK(因为它的序列号空间才刚刚开始于Seq=0,而服务器却确认了369)。为了维护协议状态的一致性,客户端认为这是一个无效或异常的连接尝试,于是发送RST强制中断这次连接。

解读:这是一种安全且正确的协议行为。客户端通过RST告诉服务器:“我无法处理你这个响应,请彻底重置这个连接。”

#8: [TCP Port numbers reused] 1031 → 1883 [SYN]

  • 含义:几乎在同一时刻(抓包时间间隔极短),客户端立即重用同一个本地端口(1031),再次向服务器的同一端口(1883)发送了一个新的SYN包,试图建立连接。

  • 异常点TCP Port numbers reused警告提示,一个新的连接尝试使用了与之前尚未完全清理的连接相同的四元组(源IP、源端口、目标IP、目标端口)

解读:这通常是客户端程序重连逻辑过于激进的表现。在旧连接因RST而强制关闭,但协议栈资源(如端口号可能还处于TIME_WAIT状态)尚未完全释放时,客户端就立刻尝试重连。这很容易引发连接失败或服务器端的拒绝。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐