3、TCP与UDP协议:从握手到拥塞控制,一次讲透

大家好,我是你们的老朋友。今天我们来聊聊网络编程里最核心的两个协议——TCP和UDP。说实话,我刚开始学网络的时候,觉得这两个东西就是背概念、记端口号。直到后来在项目中踩了坑,才真正明白它们的设计哲学。

嗯,咱们不搞那些虚的。直接上干货。

3.1 TCP三次握手:为什么是三次,不是两次?

TCP是面向连接的协议。什么叫「面向连接」?说白了,就是通信前先打个招呼,确认双方都在线,状态都正常。

这个打招呼的过程,就是三次握手。

三次握手的本质:客户端和服务端互相确认对方的接收能力和发送能力都是正常的。

流程是这样的:

  1. 第一次握手:客户端发送SYN包(同步序列编号),进入SYN_SENT状态。意思是:「嘿,我想跟你说话,这是我的初始序号X。」
  2. 第二次握手:服务端收到后,回复SYN+ACK包,进入SYN_RCVD状态。意思是:「收到你的请求了,这是我的初始序号Y,同时确认你的序号X+1。」
  3. 第三次握手:客户端发送ACK包,进入ESTABLISHED状态。意思是:「好的,我确认收到你的确认了,咱们开始聊吧。」

为什么一定要三次?我举个例子你就明白了。

假设只有两次握手。客户端发了个SYN,服务端回了ACK,服务端就认为连接建立了。但如果这个SYN是网络延迟重发的呢?服务端会傻傻地等数据,客户端却不知道这回事。结果就是服务端资源被白白浪费。

我的经验:我在做高并发服务器时,遇到过SYN Flood攻击。攻击者只发第一次握手,不回复第三次。服务端会一直保留半连接队列,很快内存就爆了。后来我用了SYN Cookie技术,才解决了这个问题。

3.2 TCP四次挥手:好聚好散的艺术

有连接就有断开。TCP的四次挥手,就是优雅地结束对话。

流程是这样的:

  1. 第一次挥手:主动方发送FIN包,进入FIN_WAIT_1状态。意思是:「我说完了,准备关闭连接。」
  2. 第二次挥手:被动方回复ACK包,进入CLOSE_WAIT状态。意思是:「收到你的关闭请求,但我可能还有话没说完。」
  3. 第三次挥手:被动方发送FIN包,进入LAST_ACK状态。意思是:「我也说完了,可以关了。」
  4. 第四次挥手:主动方回复ACK包,进入TIME_WAIT状态。意思是:「好的,确认收到你的关闭请求。」

这里有个关键点:TIME_WAIT状态会持续2MSL(最大报文生存时间)。为什么要等这么久?

你想想看,如果最后一次ACK丢了,被动方会重发FIN。如果主动方直接关闭了,就收不到这个重发的FIN,被动方就会一直等。所以TIME_WAIT是为了确保被动方能收到最后的ACK。

我曾经踩过的坑:有一次线上服务频繁报错,发现是TIME_WAIT连接太多,把端口耗尽了。后来我调整了内核参数,缩短了TIME_WAIT时间,才恢复正常。嗯,这里要注意,生产环境一定要监控TIME_WAIT的数量。

3.3 TCP流量控制:别发太快,我消化不了

流量控制,说白了就是「接收方告诉发送方:你慢点,我快撑不住了」。

TCP用滑动窗口机制来实现流量控制。接收方会在ACK包里带上自己的窗口大小(win字段),告诉发送方自己还能接收多少数据。

举个例子:

  • 接收方说:「我的窗口是4096字节。」
  • 发送方就只发4096字节的数据。
  • 接收方处理完后,窗口变大了,再告诉发送方:「现在窗口是8192了,可以多发点。」

如果接收方的窗口变成0了,发送方就会停止发送,进入零窗口探测状态。发送方会定期发一个探测包,看看接收方的窗口是不是恢复了。

我的建议:在写网络程序时,如果发现发送速度上不去,先别急着怀疑带宽。检查一下接收方的处理能力,很可能是因为窗口太小导致的。

3.4 TCP拥塞控制:别把网络堵死了

流量控制是点对点的,拥塞控制是全局的。它要解决的是「大家都别发太快,不然整个网络都堵了」的问题。

TCP的拥塞控制有四个阶段:

  1. 慢启动:刚开始时,拥塞窗口(cwnd)很小,每收到一个ACK,窗口翻倍。指数增长,直到达到慢启动阈值(ssthresh)。
  2. 拥塞避免:超过ssthresh后,窗口线性增长,每次加1。慢慢试探网络的极限。
  3. 快速重传:收到3个重复的ACK,说明有包丢了。不等超时,立即重传。
  4. 快速恢复:发生丢包后,ssthresh减半,cwnd设为ssthresh+3,然后进入拥塞避免阶段。

你可能会问:「为什么丢包就认为是拥塞?」

嗯,这是TCP的默认假设。在传统网络中,丢包的主要原因就是路由器缓存满了。虽然现在有些丢包是无线信号不好导致的,但TCP依然沿用这个假设。

核心思想:TCP的拥塞控制是一种「加法增、乘法减」的策略。网络好时慢慢加,网络差时快速减。

3.5 UDP的特点:简单粗暴,但快

UDP和TCP完全是两个极端。它没有三次握手,没有四次挥手,没有流量控制,没有拥塞控制。说白了,就是「我发我的,你收不收得到是你的事」。

UDP的特点:

  • 无连接:不需要建立连接,直接发数据。
  • 不可靠:不保证数据到达,不保证顺序。
  • 无状态:不维护连接状态,资源消耗小。
  • 速度快:没有握手、确认、重传等开销。

UDP的应用场景:

  • 视频直播:丢几帧没关系,但延迟必须低。
  • 在线游戏:玩家的操作需要实时传输,偶尔丢包可以接受。
  • DNS查询:查询包很小,重传成本低。
  • 物联网设备:设备资源有限,跑TCP太奢侈。

我的经验:有一次做视频会议系统,一开始用的TCP,结果延迟高得离谱。后来换成UDP,配合FEC(前向纠错)技术,效果好了很多。说白了,选协议要看业务场景,没有银弹。

3.6 TCP与UDP的对比

咱们用一张表来对比一下:

特性 TCP UDP
连接方式 面向连接 无连接
可靠性 可靠传输,保证顺序 不可靠,可能丢包乱序
流量控制 有(滑动窗口) 无
拥塞控制 有(慢启动、拥塞避免等) 无
速度 较慢(有握手和确认开销) 较快(无额外开销)
头部大小 20-60字节 8字节
应用场景 文件传输、网页浏览、邮件 视频直播、游戏、DNS

3.7 知识体系图

下面这张图,帮你理清本章的知识结构:

TCP与UDP协议 TCP协议 三次握手 四次挥手 流量控制 拥塞控制 UDP协议 无连接 不可靠 速度快 应用场景 TCP vs UDP 对比 可靠性 vs 速度 复杂 vs 简单 有状态 vs 无状态

好了,TCP和UDP的核心内容就这些。记住一句话:TCP追求可靠,UDP追求速度。选哪个,看你的业务场景。

可可精品资料库