UDP(User Datagram Protocol)是一种无需建立连接的数据传输协议,运行在IP之上,在发送数据报时提供最低延迟。与TCP不同,UDP不保证传递、数据包顺序或防重复保护。根据IETF RFC 768(2024)数据,UDP处理全球超过40%的互联网流量,这得益于视频通话、流媒体和DNS查询。
要点
UDP(User Datagram Protocol)是TCP/IP模型传输层的核心协议之一,由David Reed于1980年开发。它提供最低限度的数据传输机制:应用程序发送数据报,协议不追踪是否到达接收方。
UDP头部仅由四个字段组成:源端口、目标端口、长度和校验和。每个字段占用2字节,因此头部总大小为8字节。相比之下,不带选项的TCP头部占用20字节,带选项则可达60字节。
该协议不支持在自己的层面进行分片——如果数据报超过MTU(最大传输单元),则在IP层面进行分片。当某个分片丢失时,整个数据报被丢弃,因为UDP无法请求单独分片的重传。开发者必须控制数据报大小——对于移动网络,MTU通常为1400字节,因此最大大小不应超过此值。
使用UDP的应用程序创建一个SOCK_DGRAM类型的套接字,指定目标端口和IP地址,然后发送数据报。协议添加最小头部并将数据包传递给IP层。接收方监听其端口并从传入的数据报中提取数据。
UDP不执行拥塞控制——应用程序可以以网络支持的最大速度发送数据报。这可能导致信道过载,但在实时场景中,这种激进方式是合理的:对于视频通话,带有可能损失的数据流比停止传输更重要。
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(b'Hello, UDP!', ('192.168.1.100', 8888))
sock.close()
在示例中,为UDP创建了一个SOCK_DGRAM套接字。sendto方法无需建立连接即可发送数据报——只需知道接收方的IP和端口。服务器端的recvfrom方法同时返回数据和发送方地址以供回复。移动平台上的UDP套接字配置类似,但需要额外权限:在iOS上需要为非加密UDP连接添加NSAppTransportSecurity,在安卓上则需要在清单中添加INTERNET权限。
在速度比可靠性更重要的场景中,选择UDP是合理的。该协议不浪费时间建立连接、确认和重传——这提供了最低延迟,但要求开发者自行处理丢包问题。
| 优点 | 缺点 |
|---|---|
| 低延迟 — 无需握手 | 无传递保证 |
| 更小的头部 — 8字节 | 无拥塞控制 |
| 支持广播和多播 | 可能出现重复数据包 |
| 数据报独立性 — 无队列 | 数据报大小受MTU限制 |
在移动应用中,UDP通过诸如WebRTC等框架使用,这些框架在UDP之上添加了丢包控制、自适应比特率和抖动缓冲。这提供了速度优势而没有原始协议的缺点。
UDP的另一个重要方面是缺乏拥塞控制。在TCP中,Slow Start和Congestion Avoidance算法在丢包时降低传输速度,以避免网络过载。UDP没有此类机制,因此开发者必须实现自己的速度控制策略——例如,视频通话中的自适应比特率或游戏服务器中的速率限制,以防止网络信道过度过载。
UDP在延迟容忍度比丢包容忍度更重要的场景中不可或缺。让我们看看该协议在移动和Web开发中的主要应用领域。
基于UDP的RTP和RTSP协议用于实时传输音频和视频流。WebRTC——浏览器和移动应用中视频通话的标准——使用UDP作为媒体数据的主要传输方式,使用TCP进行信令。30fps视频中单个数据包的丢失对用户来说是不可察觉的,这与重传延迟不同,后者会导致明显的画面冻结。
多人在线射击游戏和MOBA需要低于50毫秒的延迟才能正确同步。UDP比TCP更快地传输玩家位置、射击和事件,数据包丢失被直接忽略——下一次更新将在16–33毫秒内到达。流行的游戏引擎,包括Unity和Unreal Engine,通过自己的传输层使用UDP,并通过应用层确认来为关键事件增加可靠性。
DNS查询在端口53上使用UDP,因为每个查询都是一个小的数据报(通常不超过512字节)。如果未收到响应,客户端只需在超时后重复查询,这比使用三次握手的TCP连接建立更快。DHCP也运行在UDP之上,因为客户端还没有IP地址,无法建立TCP连接,而广播UDP数据包可以在本地网络中查找DHCP服务器。
在UDP和TCP之间进行选择是速度和可靠性之间的权衡。每个协议对其任务类别都是最优的,理解它们的差异有助于在移动应用网络交互设计中做出正确的架构决策。
| 标准 | UDP | TCP |
|---|---|---|
| 建立连接 | 不需要 | 三次握手 |
| 头部 | 8字节 | 20–60字节 |
| 传递保证 | 否 | 是,带确认 |
| 排序 | 否 | 是 |
| 拥塞控制 | 否 | 是(AIMD、Slow Start) |
| 应用 | 流媒体、游戏、DNS | 网页、邮件、文件、API |
在移动项目中,通常采用混合方法:TCP用于可靠请求(认证、数据加载),UDP用于媒体流。QUIC——基于UDP的现代Google协议——结合了UDP的速度和TCP的可靠性,已用于HTTP/3。
我们来看一个简单的Python UDP服务器,它接收客户端消息并发送回复。服务器监听8888端口,并在无限循环中处理传入的数据报。
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(('0.0.0.0', 8888))
print('UDP服务器已在8888端口启动')
while True:
data, addr = server.recvfrom(1024)
print(f'从{addr}收到:{data.decode()}')
server.sendto(b'OK', addr)
服务器创建UDP套接字,绑定到8888端口,并等待传入的数据报。recvfrom返回数据和客户端地址,从而允许通过sendto回复。与TCP不同,服务器不存储连接状态——每个数据报独立处理。这使得UDP服务器可扩展:一台服务器可以处理数百万客户端,而无需为每个单独连接分配内存,这对于DNS服务器和游戏匹配系统非常重要。
在移动开发中,UDP通常通过高级库使用。例如,iOS的CocoaAsyncSocket提供了带有委托和GCD的UDP套接字,用于异步事件处理。在安卓上,DatagramSocket类是标准java.net库的一部分,不需要额外依赖。对于Flutter,有udp包提供简单的接口,无需配置原生套接字即可收发数据报。
值得注意的是,许多移动网络和企业防火墙会阻止UDP流量,尤其是在1024以上的端口。如果您的应用程序使用UDP,必须提供TCP回退或通过STUN服务器检查协议可用性,就像WebRTC所做的那样。在iOS上,系统框架Network.framework与NWConnection同时支持TCP和UDP,根据可用性自动选择最佳协议。对于实时应用,还建议实施自适应比特率,在丢包时降低流质量,确保即使在不稳定且错误率高的信道上也能连续播放。
常见问题
UDP不建立连接,不保证数据包传递,因此比TCP更快。UDP头部—8字节,而TCP为20–60字节。UDP适用于流媒体和游戏,TCP适用于Web请求和文件传输。
数据报是一个独立的数据包,带有UDP头部(源端口、目标端口、长度、校验和)。每个数据报独立处理,与之前的数据报无关。数据报大小受网络MTU限制,根据规范最大为65507字节。
UDP不提供传输层的可靠性——由应用程序实现。开发者添加序列号、校验和、重发请求和纠错。FEC(前向纠错)可以在不重传的情况下恢复丢失的数据包。
UDP不适用于数据完整性至关重要的场景:文件传输、银行交易、REST-API。在这些情况下,TCP保证每个字节按正确顺序到达。UDP也不建议用于高丢包率的不稳定信道。
QUIC是一种基于UDP的传输协议,由Google开发并由IETF标准化为RFC 9000。它结合了UDP的速度和TCP的可靠性,支持无阻塞多路复用和内置加密。HTTP/3使用QUIC作为传输层。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。