第12章 UDP与TCP对比:可靠性、有序性、面向连接 vs 无连接、应用场景选择
说实话,TCP和UDP这两个协议,是网络编程里绕不开的坎儿。我刚开始学的时候,总觉得TCP是「正经协议」,UDP就是个「野路子」。后来踩过几次坑才明白——没有哪个更好,只有哪个更合适。
这一章,咱们就把它们俩掰开揉碎了对比一下。我会结合自己这些年做项目的经验,聊聊什么时候该用TCP,什么时候UDP反而更香。
12.1 核心差异:一张表说清楚
先看个对比表格,心里有个底:
| 特性 | TCP | UDP |
|---|---|---|
| 连接方式 | 面向连接(三次握手) | 无连接(直接发) |
| 可靠性 | 可靠传输(确认重传) | 不可靠(丢包不重传) |
| 有序性 | 保证数据按序到达 | 不保证顺序 |
| 传输效率 | 较低(头部20字节+控制开销) | 较高(头部8字节) |
| 流量控制 | 有(滑动窗口) | 无 |
| 拥塞控制 | 有(慢启动、拥塞避免) | 无 |
| 数据边界 | 流式(无边界) | 报文(有边界) |
| 典型应用 | HTTP、FTP、SMTP | DNS、视频流、游戏 |
这张表我建议你存一下。面试的时候,面试官问「TCP和UDP的区别」,你把这几个维度一摆,基本就稳了。
12.2 面向连接 vs 无连接
这是最根本的区别。
TCP是面向连接的。什么意思?就是通信之前,双方得先「握手」——三次握手建立连接,完了还得「挥手」——四次挥手断开连接。我当年第一次写TCP服务器,看到三次握手的抓包,觉得这玩意儿真讲究,像极了两个人见面先寒暄两句再谈正事。
UDP是无连接的。它不管对方在不在,直接把数据包扔出去。你想想看,就像你往人群里喊一嗓子,听见没听见全看缘分。我做过一个UDP日志收集系统,发送端只管发,接收端能收多少算多少。这种设计在丢包容忍度高的场景下,效率确实高。
核心理解:TCP像打电话——先拨号、接通、通话、挂断。UDP像寄明信片——写好地址扔邮筒,对方收不收得到,你管不着。
12.3 可靠性:TCP的「保险箱」vs UDP的「漂流瓶」
TCP的可靠性,说白了就是「确认+重传」机制。发送方发了数据,得等接收方回一个ACK。如果超时没收到ACK,TCP会自动重发。我调试过一个TCP文件传输程序,网络偶尔抖动一下,TCP默默重传了几次,文件最后完整到达——用户完全没感知。
UDP呢?它只管发,不负责。丢包了?那是你应用层的事。我曾经在一个视频监控项目里用UDP传视频帧,偶尔丢几帧画面花一下,但整体流畅度比TCP好太多。为什么?因为TCP发现丢包会重传,重传导致延迟,延迟导致画面卡顿——用户宁愿看到花屏,也不愿看到卡顿。
我的经验:如果你做的是文件传输、数据库同步、远程控制这类「数据必须完整」的应用,老老实实用TCP。如果你做的是实时音视频、在线游戏、监控数据采集这类「可以丢一点但不能卡」的应用,UDP更合适。
12.4 有序性:TCP的「排队」vs UDP的「抢跑」
TCP保证数据按发送顺序到达。为什么能做到?因为每个TCP包都有一个序列号,接收方按序列号组装数据。如果包3先到了,包2还没到,TCP会先把包3缓存起来,等包2到了再一起交给应用层。
UDP不保证顺序。你发了包1、包2、包3,接收方可能先收到包3,再收到包1,最后收到包2。我做过一个UDP游戏协议,角色移动指令经常乱序——角色先走到B点,再走到A点,看起来就像瞬移。后来我在应用层加了个序列号,自己排序,才解决了这个问题。
注意:UDP的有序性问题,应用层必须自己处理。不要指望UDP帮你排好序——它没这个能力,也没这个义务。
12.5 应用场景选择:什么时候选谁?
这个问题,我直接给你一个决策流程:
- 数据必须完整到达吗?是→TCP,否→看第2条
- 延迟敏感吗?是→UDP,否→看第3条
- 数据量小且频繁吗?是→UDP(减少连接开销),否→TCP
举个例子:
- Web浏览(HTTP):必须完整,延迟不太敏感→TCP
- 视频直播:可以丢帧,延迟敏感→UDP
- DNS查询:数据小,一次请求一次响应→UDP(默认)
- 邮件发送(SMTP):必须完整,延迟不敏感→TCP
- 在线游戏:位置更新可以丢,延迟敏感→UDP
我做过一个物联网项目,传感器每隔几秒上报一次温度数据。一开始用的TCP,结果设备多了,服务器连接数暴涨,内存吃紧。后来改成UDP,每个传感器发一个UDP包,服务器无状态接收,轻松扛住了十万级设备。你看,选对协议,事半功倍。
12.6 知识体系图
下面这张图,把TCP和UDP的核心差异和应用场景串起来了:
12.7 避坑指南
最后,分享几个我踩过的坑:
- 别在UDP上实现TCP:我见过有人想在UDP上自己实现可靠传输、有序到达、拥塞控制——结果搞出来的东西既没有TCP稳定,又没有UDP高效。如果你需要可靠性,直接用TCP,别自己造轮子。
- UDP缓冲区要设大一点:默认的UDP接收缓冲区可能只有几十KB,高并发场景下很容易丢包。我习惯把SO_RCVBUF设到1MB以上。
- TCP的Nagle算法可能坑你:做实时交互时,Nagle算法会把小包攒起来再发,导致延迟飙升。我一般会设置TCP_NODELAY来禁用这个算法。
- UDP的MTU问题:UDP包超过MTU(通常1500字节)会被分片,分片丢失会导致整个包重传。我习惯把UDP数据控制在1400字节以内。
一句话总结:TCP让你睡得安稳,UDP让你跑得更快。选哪个,看你更在乎什么。
公众号:蓝海资料掘金营,微信deep3321