3、TCP/IP协议栈核心(下):TCP三次握手与四次挥手、TCP滑动窗口与流量控制、UDP协议特点
3.1 TCP三次握手:建立连接的那点事
说到TCP,绕不开的就是三次握手。说白了,就是客户端和服务器在正式传数据之前,先互相打个招呼,确认双方都在线、都愿意聊。
我刚开始做DTU项目时,总觉得三次握手有点啰嗦。后来在野外调试一个4G模块,发现设备老是连不上服务器,抓包一看——握手只完成了两次,第三次丢了。嗯,从那以后我再也不敢小看这三次握手了。
具体流程是这样的:
- 第一次握手(SYN):客户端发送一个SYN包,告诉服务器“我想跟你建立连接”。此时客户端进入SYN_SENT状态。
- 第二次握手(SYN+ACK):服务器收到后,回复一个SYN+ACK包,意思是“收到你的请求,我也准备好了”。服务器进入SYN_RCVD状态。
- 第三次握手(ACK):客户端再发一个ACK包,确认“好的,我知道了”。双方都进入ESTABLISHED状态,连接建立成功。
关键点:三次握手的核心是确认双方的收发能力都正常。第一次握手证明客户端能发,第二次握手证明服务器能收能发,第三次握手证明客户端能收。少一次都不行。
实战经验:我在调试工业DTU时,经常遇到握手超时的问题。原因往往是SIM卡信号弱,或者服务器端防火墙把SYN包给丢了。我的习惯是先用ping测通,再用telnet测端口,最后才抓包看握手过程。
3.2 TCP四次挥手:好聚好散的艺术
有建立就有断开。四次挥手比三次握手多了一次,为什么?因为TCP是全双工的,两边都要独立关闭自己的数据通道。
流程是这样的:
- 第一次挥手(FIN):主动关闭方(比如客户端)发送FIN包,告诉对方“我这边没数据要发了”。
- 第二次挥手(ACK):被动关闭方回复ACK,表示“收到你的FIN,但我还有数据要发”。
- 第三次挥手(FIN):被动关闭方发完所有数据后,也发送FIN包,说“我这边也发完了”。
- 第四次挥手(ACK):主动关闭方回复ACK,确认收到。然后进入TIME_WAIT状态,等待2MSL后彻底关闭。
注意:TIME_WAIT状态是个坑。我记得有一次在服务器上跑DTU数据采集程序,发现端口被占满了,一查全是TIME_WAIT。原因是客户端频繁重连,服务器来不及释放端口。解决方案是调整tcp_tw_reuse和tcp_tw_recycle参数,或者干脆用长连接。
你想想看,如果客户端直接发RST包强制断开,服务器那边可能还有数据没发完,数据就丢了。所以四次挥手是必要的“好聚好散”。
3.3 TCP滑动窗口:流量控制的秘密
滑动窗口,说白了就是TCP的流量控制机制。它解决了一个很实际的问题:发送方发得太快,接收方处理不过来怎么办?
我个人的理解是:滑动窗口就像一条流水线。发送方有一个“已发送未确认”的窗口,接收方有一个“可用缓冲区”的窗口。双方通过窗口大小来协商传输速度。
核心概念:
- 发送窗口:发送方可以连续发送的数据量,不需要等待ACK。
- 接收窗口(rwnd):接收方告诉发送方“我还有多少缓冲区可用”。
- 拥塞窗口(cwnd):网络状况决定的窗口大小,防止网络拥塞。
实际窗口大小 = min(rwnd, cwnd)。
举个例子:假设接收窗口是4096字节,发送方一次发了3000字节,还没收到ACK。此时发送窗口还剩1096字节。如果接收方处理完数据,回复ACK并告知新的rwnd=8192,发送窗口就变大了。
我在项目中遇到过一个问题:DTU上报数据时,服务器端处理太慢,导致接收窗口逐渐缩小到0。发送方只能不断发送零窗口探测包,白白浪费带宽。后来我在服务器端加了异步处理队列,才解决了这个问题。
3.4 UDP协议特点:简单粗暴但高效
聊完TCP,再来说说UDP。UDP和TCP是两种截然不同的性格。TCP是“靠谱的老大哥”,UDP是“随性的小年轻”。
UDP的特点:
- 无连接:不需要三次握手,直接发数据。
- 不可靠:不保证数据到达,不保证顺序,不保证不重复。
- 无流量控制:发多少算多少,接收方处理不过来就丢包。
- 低开销:头部只有8字节,比TCP的20字节小得多。
| 特性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接 | 无连接 |
| 可靠性 | 可靠 | 不可靠 |
| 头部大小 | 20-60字节 | 8字节 |
| 传输速度 | 较慢 | 较快 |
| 适用场景 | 文件传输、网页浏览 | 视频流、DNS查询、IoT传感器数据 |
我的建议:在DTU通信中,如果数据量小、实时性要求高、可以容忍偶尔丢包,用UDP更合适。比如环境传感器每隔几秒上报一次温度数据,丢一包无所谓。但如果传输配置参数或固件升级,必须用TCP。
我曾经在一个智能水表项目中,用UDP上报数据。结果发现运营商网络对UDP不太友好,经常丢包。后来我在应用层加了个简单的确认重传机制——说白了就是自己实现了一个“迷你TCP”。虽然麻烦了点,但效果不错。
3.5 总结:TCP vs UDP,怎么选?
选TCP还是UDP,没有绝对的对错。我的经验是:
- 数据必须完整到达:选TCP。比如固件升级、配置下发。
- 实时性优先,丢包可接受:选UDP。比如实时监控、语音通话。
- 网络环境差:选TCP。UDP在弱网环境下丢包率太高。
- 资源受限的设备:可以考虑UDP,因为TCP协议栈开销大。
嗯,TCP/IP协议栈核心的内容就讲到这里。下一章我们会深入DTU的通信协议设计,看看怎么在实际项目中用好这些知识。