1. UDP协议概述:它在协议栈里的位置、与TCP的核心区别、以及我为什么离不开它
各位好,我是老周。今天咱们开始聊UDP协议。说实话,UDP这玩意儿在很多人眼里就是个“不可靠的传输协议”,甚至有些刚入行的朋友觉得它就是个“阉割版TCP”。嗯,这种看法其实挺片面的。我在做流媒体传输那几年,UDP可是我的主力工具。
先搞清楚一件事:UDP不是设计缺陷,而是设计取舍。它把可靠性交给上层应用,自己只做一件事——把数据从A点扔到B点,越快越好。
1.1 UDP在TCP/IP协议栈中的位置
TCP/IP四层模型,从上到下分别是:应用层、传输层、网络层、网络接口层。UDP和TCP一样,都坐在传输层这个位置上。
关键点:UDP直接封装在IP数据报里,协议号是17。你抓包的时候看到IP头里Protocol字段是17,那就是UDP。
我画了一张图,帮你把UDP在协议栈里的位置看清楚:
你看,UDP和TCP在传输层是平级的。应用程序可以选择用TCP还是UDP,甚至自己实现一套传输协议。我当年做视频会议系统时,就是在UDP之上自己搭了一套可靠传输——因为TCP的拥塞控制太“老实”了,不适合实时场景。
1.2 UDP与TCP的核心区别
说白了,TCP是个“老好人”,UDP是个“急先锋”。TCP要握手、要确认、要重传、要保序;UDP呢?发出去就不管了。
我整理了一张对比表,你一看就明白:
| 对比维度 | TCP | UDP |
|---|---|---|
| 连接方式 | 面向连接(三次握手) | 无连接(直接发) |
| 可靠性 | 可靠传输(确认+重传) | 尽最大努力交付(不保证) |
| 数据顺序 | 保序(按序交付) | 不保序(可能乱序) |
| 流量控制 | 有(滑动窗口) | 无 |
| 拥塞控制 | 有(慢启动、拥塞避免) | 无 |
| 首部开销 | 20~60字节 | 8字节固定 |
| 传输模式 | 字节流 | 数据报(有边界) |
| 典型场景 | 网页、文件传输、邮件 | DNS、DHCP、视频流、游戏 |
我的经验:UDP首部只有8字节,TCP最少20字节。别小看这12字节的差距,在高频交易场景下,每微秒都是钱。我曾经优化过一个行情推送系统,从TCP切到UDP后,延迟直接降了40%。
你可能会问:UDP这么“不靠谱”,为什么还要用它?原因很简单——有些场景下,可靠性反而是累赘。
举个例子:你在看视频直播,偶尔丢一帧画面,顶多卡顿一下。但如果用TCP,丢包后它会重传,重传的数据到了也没用了——画面已经过去了。这就是所谓的“迟到比不到更糟糕”。
1.3 UDP的应用场景
UDP的应用场景,说白了就三个字:快、轻、简。我挑几个典型的说说:
1.3.1 DNS(域名解析)
你每次访问网站,浏览器都要先做DNS查询。DNS查询默认用UDP 53端口。为什么?因为查询报文就几十个字节,用TCP建立连接的开销比查询本身还大。你想想看,为了问一句“www.example.com的IP是多少”,先花三个报文握手,是不是太浪费了?
注意:DNS也支持TCP,但只在响应超过512字节(现在通常是1232字节)或区域传输时才会切到TCP。我排查过一个DNS超时问题,最后发现是UDP报文被防火墙截了,客户端等超时后才切TCP——白白浪费了5秒。
1.3.2 DHCP(动态主机配置协议)
你的电脑插上网线就能上网,靠的就是DHCP。DHCP全程用UDP,客户端用68端口,服务器用67端口。为什么不用TCP?因为DHCP在分配IP之前,客户端连自己的IP都没有,TCP的三次握手根本建立不起来。这是个典型的“先有鸡还是先有蛋”的问题。
我记得有一次帮客户排查网络故障,发现DHCP请求发不出去。抓包一看,交换机上配了DHCP Snooping,但信任端口没设对。嗯,这种坑踩过一次就记住了。
1.3.3 视频流与实时通信
这是UDP的主战场。RTP(实时传输协议)就是跑在UDP之上的。视频会议、直播、VoIP,底层全是UDP。我参与过一个在线教育平台,最初用TCP推流,结果网络一波动就卡成PPT。后来换成UDP + FEC(前向纠错),用户体验直接起飞。
为什么会这样?因为视频流对延迟敏感,但对丢包有一定容忍度。丢一个包,画面花一帧,下一帧就恢复了。如果用TCP重传,整个画面都得等,反而更糟。
1.3.4 在线游戏
你玩《王者荣耀》或《绝地求生》时,网络传输用的就是UDP。游戏里你按一下技能,这个操作必须立刻发出去。如果用TCP,万一丢包了要重传,等你技能到了,人早就凉了。游戏引擎通常会在UDP之上做自己的可靠性保障——比如只重传关键操作(如购买装备),非关键操作(如移动)丢了就丢了。
1.3.5 SNMP(简单网络管理协议)
网络设备(交换机、路由器)的监控告警,很多走的是SNMP。SNMP默认用UDP 161/162端口。为什么?因为网络设备CPU资源有限,跑TCP的开销太大。而且监控数据丢了就丢了,下一轮采集马上补上。
避坑指南:我曾经遇到过SNMP告警丢失的问题。排查后发现是UDP接收缓冲区太小,流量一高就丢包。解决方案很简单:调大net.core.rmem_default和net.core.rmem_max。Linux下默认的UDP接收缓冲区只有208KB,高并发场景下根本不够用。
1.4 什么时候该用UDP?
我个人的判断标准很简单,三条:
- 能容忍丢包——丢了不影响核心功能,或者应用层自己能处理
- 对延迟敏感——宁可丢包也不愿等重传
- 报文短小且独立——一次查询一次响应,不需要维持长连接
满足任意两条,UDP就是你的首选。如果三条都满足——那UDP简直是为你量身定做的。