1. 别急着选协议:先搞清楚你的业务到底要什么
1.1 “稳不稳”是个伪命题:可靠性不是TCP的专属
很多人第一次接触TCP和UDP,头脑里就固化了一句话:“TCP是可靠的,UDP是不可靠的,所以能不选UDP就不选UDP。”
这句话本身没有错,但它害了不少人。因为在真实的工程场景里,“可靠”是一个被过度简化的概念。TCP的可靠性是传输层的可靠性:它保证你发的字节流最终按顺序到达对端。可你业务真正需要的“可靠”往往是另一回事——数据不丢、消息不重、处理不阻塞、服务不挂。
我见过一个真实案例。有人用TCP做了一个日志上报系统,结果发现服务端偶尔收不到日志,大家第一反应是TCP丢了数据。但抓包一看,TCP一条都没丢,是客户端内存缓冲积压,服务端处理不过来,TCP把数据送来了,应用层没来得及落盘,进程一重启就全没了。你看,TCP再可靠,也管不到应用层。
所以第一步要纠正的不是“选TCP还是UDP”,而是“你说的可靠,到底是哪一层的可靠”。TCP能保证的是“面向连接、字节流、有序、不丢包”这件事本身,但代价是什么,后面会拆开讲。而UDP也并不是“不可靠”的代名词,它只是“不替你负责”,你可以在UDP之上自己做可靠机制,也可以完全不需要可靠机制。
1.2 把需求拆成六个关键问题
既然「别背概念,用场景做决策」,那决策的起点就是把自己的业务需求翻译成协议能回答的问题。我这些年做选型,习惯先回答以下六个问题:
| 判断维度 | 偏向TCP的信号 | 偏向UDP的信号 |
|---|---|---|
| 时延要求 | 能容忍几百毫秒延迟,比如订单接口 | 要求稳定低时延,比如音视频、云游戏 |
| 数据丢失后果 | 丢一条消息可能出大问题,比如支付、控制指令 | 丢一两帧能接受,比如图像采集、状态刷新 |
| 消息大小和频率 | 大数据块、低频交互,比如文件、查询 | 小报文、高频周期性上报,比如遥测、心跳 |
| 对网络拥塞的态度 | 希望网络变差时自动减速度,让出带宽 | 哪怕网络拥塞也要维持实时性,不能干等 |
| 弱网概率 | 跨公网、跨运营商、移动网络 | 局域网、专线、可控网络 |
| 团队维护成本 | 不想写太复杂的应用层逻辑 | 愿意为高性能承担更复杂的编码 |
你把这六个问题逐项写下来,大多数情况已经能得出一个倾向性的答案了,根本不需要背概念。
1.3 这一步没做对,后面全是坑
这六条里最容易踩坑的是第一条和第二条——时延和丢包容忍度。很多人做实时数据展示时默认选TCP,理由是“数据不能丢”。结果在网络抖动时,TCP因为重传和拥塞控制,把所有的数据都“堵”在了半路上,界面直接卡成PPT。反观UDP,数据丢了就丢下一帧,画面最多闪一下。
反过来,也见过有人为了追求性能,用UDP做设备控制指令的传输,结果指令在弱网下丢了,设备没动作,然后就是事故。这种场景控制指令丢一条都是大事,哪怕牺牲一点时延,也得选TCP或自己做很强的应用层确认。
所以我的经验是:先写清楚业务对丢包的容忍边界和时延上限,再谈协议,这一步不做好,后面设计通信架构全是坑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. TCP的“可靠”背后,是三笔不能回避的工程账
2.1 三次握手的成本:不只是三包数据
TCP建立连接需要三次握手,这个知识点大家都会背:SYN、SYN+ACK、ACK。但很多人不知道,这背后是一笔工程账。
第一笔账是时延。三次握手至少要一个RTT(往返时间),跨省跨国的公网RTT轻松到几十甚至上百毫秒。如果你的业务是高频短连接——比如每次采集数据都新建一个TCP连接——那光建立连接的时间就已经超过业务本身的预算了。我当时调一个小型数据采集系统时,测试发现大量时间消耗在tcp连接建立上,后来改成常连接,性能立刻上来了。
第二笔账是端口和状态。每个TCP连接在服务端都要占用一个文件描述符和内核内存;主动关闭的一方还会进入TIME_WAIT状态,在2MSL(最大报文段生存时间,通常60秒左右)内端口不能立即重用于同样的四元组。你如果用TCP做百万级并发短连接,光是TIME_WAIT的连接管理就够头疼的。这也是为什么很多高并发网关宁愿用UDP自己维护会话,或者直接上QUIC。
UDP的连接成本是0。无连接,发数据前不用握手,不需要维护连接状态,也不用为每个会话保留一大堆内核结构。这种“轻”在特定场景下是巨大优势。
2.2 拥塞控制与重传:网络越差,TCP越“慢”
TCP内部有拥塞控制算法。网络一旦出现丢包或明显延迟增加,TCP会判断为拥塞,把拥塞窗口降下来,重传丢失的数据,并且降低发送速率。这套机制保证了TCP不会把网络打爆,但也意味着:网络越差,TCP表现得越保守、越慢。
之前做跨公网的文件传输,拉一个30MB的文件,局域网内秒传,到了公网上速度直接掉到几百KB/s。抓包看,大量重复ACK,发送窗口不断减半,中间还有超时重传。TCP在尽力保证数据完整,但它不管你的业务有多着急,它的第一优先级是“别把网络搞挂”。
很多人问“TCP比UDP更省流吗”,其实不是。TCP不会刻意省流量,它只是会在拥塞时主动降速,所以看起来“更省”;UDP本身没有任何拥塞控制,应用程序想发多块就发多块,流量用满带宽,但不会因为网络问题自动变慢。你要是拿UDP做无脑大流量发送,很快就会被网络设备限速或丢弃。
2.3 队头阻塞:应用层看不到的隐形杀手
TCP是字节流协议,保证数据的顺序和完整性。这意味着接收端的TCP栈必须把数据按序号排好,再交给应用层。如果中间有一个包丢了,即使后面的包都到了,也要先在缓冲区里等着,直到丢失的包重传成功。
这就叫队头阻塞。用白话讲:一条车道上前面出了事故,后面所有的车都得停下来等,哪怕你自己的车没有任何问题。
这个特性对文件传输、网页浏览是无所谓的,顺序本来就重要。但对实时音视频、互动直播、游戏操作指令这种场景,队头阻塞是致命的。视频通话中,一帧画面丢了,用户宁愿看到这一帧卡一下或者干脆跳过,也不希望后面所有数据都停住等待重传。而TCP做不到“跳过去”,它只会“等”。
2.4 什么时候选TCP
说了这么多TCP的代价,不是让你别用它。反过来,TCP的可靠传输、拥塞控制、成熟生态,在多数业务里依然是首选。
具体来说,这些场景选TCP就非常合理:
- HTTP/HTTPS协议的Web API和Web应用
- 文件上传下载、日志采集与同步
- 数据库主从复制、消息队列的持久化传输
- 需要严格顺序处理的指令流
- 通过MQTT、Modbus TCP等基于TCP的应用协议通信
另外,选TCP还有一个隐藏的工作要做:字节流与消息边界的处理。TCP是流的抽象,你send两次数据,对端可能一次就recv出来;你send一次,对端也可能分两次才读完。所以应用层必须自己定义消息格式——通常是长度前缀或者分隔符。这个“粘包/拆包”问题虽然不难,但确实绕不开。
3. UDP的真实战场:它并不是“不可靠”,而是“不替你负责”
3.1 实时音视频与游戏:为什么宁可丢帧,绝不重传
为什么视频会议、实时直播、在线游戏这些场景几乎都离不开UDP?因为它们的核心诉求不是“数据完整”,而是“及时送达”。
实时语音如果延迟超过300ms,对话体验就会非常奇怪;FPS游戏的操作指令如果走TCP,一个丢包重传就可能让整个人物瞬移或者卡住。对于这些场景,丢掉一帧旧数据根本无所谓,用户关心的是下一秒的画面和操作能否及时出来。
所以这类应用往往采用UDP + 应用层补偿策略:丢包了就用上一帧预测当前帧,或者用FEC(前向纠错)技术提前加入冗余数据,让对方能在丢包情况下直接恢复出一部分数据。这种思路和TCP的“错了就重传”完全不同,它从根源上保证了低时延。
3.2 工业控制、ROS与嵌入式通信:确定性优先
工业现场多的是周期性的数据采集和状态上报。你比如用LabVIEW做UDP通信,场景往往是几百个传感器节点,每隔几十毫秒就往主机发一小包数据,这类流量有明确特点:包小、频率高、实时性强、不需要回执。
你要用TCP一条条建立连接、维护状态、重传,成本极高。而UDP的请求-响应模型几乎零负担。类似地,ROS2的通信底层默认是基于UDP的DDS(RTPS)协议,图的就是低时延和组播能力。注意:ROS1默认走的是TCPROS,但ROS2切换到DDS后,默认传输层就是UDP,这背后就是实时性的考量。
但也有例外。比如西门子S7-1200通过TCP用ASCII码发送数据给打印机或显示设备,Modbus TCP在工业以太网里大量使用,这些场景普遍是请求-响应、低频、需要确认的,TCP就比UDP合适。所以工业场景里TCP/UDP不是二选一的问题,而是看每一条数据流的形态。
3.3 广播发现、状态上报与网络测量:UDP的“轻”是核心优势
有些协议天然就必须是UDP,因为它们需要广播或组播。比如DHCP动态获取IP、ARP地址解析、NTP时间同步,都跑在UDP上。你想实现局域网设备自动发现,最简单的方式就是发一条UDP广播,所有同网段的设备都能收到,而TCP做不到广播。
周期性的传感器上报也适合UDP。传感器每隔几秒上报一次数据,值变了才需要更新,丢了就等下一次上报,完全没必要为每个报文建立连接。
还有一个容易被忽略的场景:网络测量。大家搜索“iperf3使用udp打流”,本质上就是用UDP去灌流量,测链路的极限带宽、抖动和丢包率。为什么不用TCP测?因为TCP自带拥塞控制,测出来的是“TCP能跑多快”,不是“链路本身能跑多快”。UDP正好相反,能不能跑满纯看链路,适合摸设备性能的底。
顺便说一句,IP头里有个字段叫Protocol,TCP的协议号是6,UDP的协议号是17。抓包的时候想快速区分,看协议号就行。
3.4 需要可靠时怎么办:应用层自己补
很多人一听UDP就慌,觉得不可靠。如果你是负责实现的那个工程师,完全可以自己给UDP加上可靠性机制:
- 报文加序号,方便对端检测丢包和乱序;
- 应用层定期发送ACK,超时未确认就重传;
- FEC前向纠错,通过冗余包恢复部分丢失的数据;
- 自定义拥塞控制逻辑,在某些场景下能比TCP更精准。
现在很多云游戏和弱网加速方案本质上就是这个思路:数据走UDP,应用层自己搞定可靠性、乱序和带宽控制。像QUIC协议这类在UDP之上实现可靠传输的框架,已经把很多能力标准化了。但我要提醒一句:自己造可靠UDP的复杂度远高于直接用TCP,如果你的场景对可靠性有硬要求,又没有专门的网络开发团队,老老实实用TCP是更理性的选择。
4. 从那些热搜问题里翻出来的真实踩坑复盘
4.1 modbus TCP能ping通但mod scan不通:应用层与传输层的错位
很多工控工程师遇到过这个场景:设备和电脑之间用ping命令能通,但用Modbus扫描工具就是扫不到设备。
这个问题的根源在于:ping走的是ICMP协议,它只证明IP层可达,不证明你要的TCP端口在监听。Modbus TCP固定走502端口,设备没开这个端口、防火墙拦掉了502、或者设备端根本没配置Modbus TCP从站,都会出现“网络通但应用不通”的现象。
排查顺序很重要。先确认对端502端口是不是真的开放监听,可以用telnet、nc或者自己写个socket程序探一下;再用抓包工具看一下TCP三次握手有没有成功、有没有发送Modbus请求;最后再查设备端的配置。这类问题教给我的不是“选TCP还是UDP”,而是 “传输层通不等于应用层通”,选型时要同时考虑应用协议、端口和连接建立方式。
4.2 西门子只能重启后连上一分钟:这不一定是协议的锅
又一个典型场景:西门子PLC用TCP和上位机通信,每次PLC重启后能连上一分钟,然后就断开或者连不上了。很多人第一反应是“TCP不可靠”,换UDP,结果更糟。
实际上这类问题大多是连接资源没释放。上位机每次建立TCP连接后没有正常关闭,PLC侧的连接数到了上限,新连接就进不来了;或者PLC内部的TCP通信处理任务有问题,连接一直处于半开状态。
排查时用抓包工具看连接建立和断开的日志。如果发现大量的FIN包没有正常交互,或者连接长时间不关闭,那问题基本就在二次开发代码里的关闭逻辑上。这种场景换成UDP也救不了,反而因为UDP没有连接状态,排查起来更困难。
4.3 docker端口暴露失败与“tcp 0.0.0.0”报错
用Docker跑容器,启动时报“ports are not available: exposing port tcp 0.0.0.0:xxxx”,这类报错的原因通常很简单:宿主机上这个TCP端口已经被别的进程占用了,docker-proxy绑定失败。
处理分几步:
netstat -tlnp | grep <端口>看是谁占用了端口;- 决定是杀掉占用进程,还是换一个宿主映射端口;
- 如果需要UDP端口,docker映射时要显式说明协议。
这里隐藏着一个容易忽略的细节:Docker的 -p 8080:80 默认映射的是TCP。如果你的容器服务同时有TCP和UDP端口,必须显式写 -p 8080/udp 或 -p 8080:8080/tcp -p 8080:8080/udp。很多人在这个点上吃了亏,容器起来了但UDP包就是收不到。
4.4 防火墙/NAT/MTU:协议选好了,链路不通仍白搭
选型选得再好,网络链路不通照样白搭。这里有几个容易被忽视的工程问题:
- 防火墙策略:UDP无连接,不像TCP那样有SYN包可以识别“连接开始”,所以很多防火墙对UDP的态度就是“要么全放,要么全拦”,缺少状态检测能力。你开放了端口,不代表所有UDP流量都能过。
- NAT超时:UDP在NAT设备上的映射表有时间限制,长时间不发数据,表项会被清除。所以UDP长连接需要定期发心跳保活。
- MTU与分片:TCP在握手时会协商MSS,可以钳制到路径MTU,但UDP没有这个机制。UDP发送大包时可能触发IP分片,而分片包一旦被中间设备丢弃且ICMP不可达消息被防火墙拦截,发送方根本不知道发生了什么,表现为“UDP大包不通,小包通”。这种情况下,要么控制UDP包大小,要么在路由器/防火墙上改MSS。用iptables做MSS钳制时常见命令里会用到
--clamp-mss-to-pmtu,本质就是让TCP自动适配路径MTU。
再补一个新手常问的问题:交换机出来的流量是TCP还是UDP?答案是不关心。交换机工作在二层转发帧,IP和传输层协议在它眼里只是payload的一部分。你做选型时不应该被设备层干扰,但必须关心防火墙、路由器安全策略对这两种协议的差别待遇。
5. 用实测数据做选型:iperf3的正确打开方式
5.1 为什么理论对比不如一次打流
网上关于TCP和UDP性能的说法有很多,但很多都是脱离环境空谈。同样是100Mbps的链路,局域网里TCP可能稳定跑满,跨公网弱网环境TCP可能只有几Mbps;UDP在完全不丢包的局域网能测出很低的抖动,在拥塞的链路上可能瞬间丢包5%以上。
所以我做选型到一个阶段,一定会做一次实测。工具就用iperf3,免费、跨平台、能测TCP和UDP,一台电脑当服务端,一台电脑当客户端,几分钟就能得出结论。
5.2 TCP模式测什么、UDP模式测什么
先看基础用法。服务端起一条命令:
iperf3 -s
TCP吞吐测试,客户端执行:
iperf3 -c 192.168.1.10 -t 30
这条命令会测30秒的TCP单向吞吐,结果会显示带宽、重传次数和总的发送量。重传数是重要参考:TCP吞吐高但重传频繁,说明网络对TCP并不友好。
UDP打流测试,客户端执行:
iperf3 -u -c 192.168.1.10 -b 100M -t 30
-u 表示走UDP,-b 100M 表示以100Mbps的速率发送。UDP模式没有拥塞控制,你不给它设置目标速率,它可能会以极快的速度把带宽打满,这本身不是问题,但测试前要清楚预期带宽。-b 也可以按实际业务估算的峰值来设。
如果还想测反向链路,加 -R 参数;想模拟多路并发,加 -P 4 表示4个并行流。
5.3 结果解读:带宽、抖动、丢包率怎么影响决策
UDP模式的结果里会输出几个关键指标:
Jitter:抖动,反映网络时延的变化程度。实时音视频对抖动敏感,一般要求抖动在毫秒级;Lost/Total Datagrams:丢包数量和丢包比例。这个数字直接对应业务容忍度;Bandwidth:实际到达服务端的速率,如果远低于-b设定的发送速率,说明链路在丢包或者设备在限速。
比如你用-b 100M打流,发现实际接收只有80Mbps,丢包率4%,那说明链路已经达到或接近瓶颈。此时如果你的业务是实时视频,就要考虑降码率、加FEC,或者换一个更宽松的网络路径;如果你的业务是文件传输,可能TCP反而比UDP更适合,因为TCP会在丢包时重传保证完整。
TCP模式的测试结果也有参考价值。TCP吞吐高且重传少,说明链路对TCP很友好;TCP吞吐低但重传高,说明链路拥塞严重,应用层要特别注意超时和重连策略。
5.4 测试中的控制变量与常见错误
打流测试看似简单,但控制不好变量结果就是废数据。几个我踩过坑的点:
- 测试两端最好都用有线连接,不要一边连Wi-Fi一边测无线,那样测出来的结果混杂了无线信号因素;
- 同一套参数多测几轮,取中间值,不要拿第一次的结果下结论;
- 关闭测试机上不必要的应用和服务,避免本地资源抢占;
- 在生产或公用网络环境做UDP打流前一定要确认影响范围,别把别人的业务打挂了。UDP洪水攻击脚本就是利用UDP无拥塞控制的特性,把大量的UDP包砸向目标,导致正常服务不可用,这在公网上是很危险的事情;
- 服务端和客户端都看一遍结果,因为两端的统计有时会有偏差。
6. 给不同场景的直接答案(可直接抄作业)
6.1 实时交互:视频通话、远程控制、游戏
这类场景第一优先级永远是时延。选UDP,并配合应用层做丢包补偿(FEC、预测、重传旧帧)。如果是因为NAT穿越原因不得不走TCP,也要尽量选支持类似QUIC思路的方案,减少队头阻塞的影响。
6.2 请求响应业务:Web API、数据库、消息队列
选TCP。这类业务天然是请求-响应模型,连接可以复用,状态清晰,生态成熟。HTTP/HTTPS、MySQL、PostgreSQL、Kafka等等,底层都是TCP,不需要你自己纠结。
6.3 文件传输与日志同步
选TCP。文件传输对完整性要求极高,日志同步通常也需要保证顺序。只有在超大文件、极弱网、对速率有极端要求的场景下,才考虑用UDP+FEC的方案,但那属于高度定制化开发,不是常规选项。
6.4 物联网与设备控制
分情况。低频控制指令建议TCP或自带确认的应用协议,因为一条指令丢了代价可能很大;高频周期遥测数据建议UDP,比如温湿度传感器每秒上报一次,丢一包没啥影响;设备发现和局域网广播,用UDP广播或组播。
6.5 一个可复制的判断流程
最后总结一个我常用的五步判断法:
- 数据丢了会怎样?(判断丢包后果)
- 时延上限是多少?(判断实时性要求)
- 消息有边界吗?(判断是否需要处理粘包/拆包)
- 网络环境我能掌控吗?(判断拥塞控制和MTU问题)
- 团队有多少时间维护应用层协议?(判断是否需要现成TCP生态)
前三个问题决定了协议的“倾向”,后两个问题决定了你是否能承受做UDP应用层的成本。
我个人的体会是:能用TCP的先用TCP,TCP满足不了再上UDP;而一旦决定用UDP,就要做好应用层补偿机制,并且用iperf3这类工具把网络底线摸清楚,让每一次决策都有数据支撑。别被“TCP可靠、UDP不可靠”这种粗颗粒度的概念牵着走,真正重要的永远是你的业务在真实网络环境下的表现。
