9.9. UDP —— 发出一个数据包,听天由命¶
UDP,即用户数据报协议(User Datagram Protocol),是传输层提供的两种服务中较简单的一种。每一次 UDP 发送都是一个 数据报——一块自包含的字节,寻址到某个 IP 和某个端口,独自被投入网络。协议会在可能的情况下投递它;如果无法投递,它不会重试,不会警告发送方,也不会保留数据报之间的任何顺序。
9.9.1. UDP 在 IP 之上增加了什么¶
UDP 是 IP 之上的一个薄层。它在原始的 IP 投递之上增加了三样东西:
两端的 端口号,使得数据报可以被投递到目标主机上正确的 程序,而不仅仅是主机(参见 端口)。
一个 长度字段,使接收方确切知道要读取多少字节的有效载荷。
一个覆盖头部和有效载荷的 小型校验和,使接收方能够检测出损坏的数据报并将其丢弃。
仅此而已。IP 做过或没做过的其他一切,UDP 全都保留下来。数据报不会被重试。它们可能乱序到达。它们可能因底层网络的怪异行为而被复制。如果网络拥塞、目标处的缓冲区已满,或者中间某个路由器决定如此,它们可能被悄无声息地丢弃。
每个 UDP 数据报都是独立发送的。如果其中一个在传输中丢失,没有任何东西会告知发送方或接收方——这个缺口是无声的。¶
9.9.2. 为什么有人会使用它¶
如果 UDP 这么不可靠,为什么还要有它?有三个原因。
速度和开销。 一次 UDP 发送就是一个数据包发出去;没有握手,没有确认,没有需要维护的连接状态。延迟和带宽成本都极小。
独立消息。 有些流量是一连串 状态更新,其中每条消息都是一份全新的快照,旧的消息毫无价值。一个每秒发布“我还活着,这是我当前的读数”的摄像头,关心的是投递每一个 新 读数,而不是重放那些丢失的读数。
组播。 单个 UDP 数据报可以一次发送给多个接收方。(TCP 做不到这一点;每条 TCP 连接都恰好在两个端点之间。)这对服务发现、向众多监听者发送遥测数据、视频流很有用。
在网络状况良好且发送方对丢失的容忍度较高的场合,UDP 是正确的答案。在必须保证投递和顺序的场合,UDP 要么需要在其之上再加一层可靠性,要么应用程序就应该直接改用 TCP。
9.9.3. 何时 不 使用它¶
反过来的情况同样值得明确说明。在以下情况下,UDP 是错误的选择:
每个字节都重要。 配置数据、代码更新、签名交易——任何一个字节缺失就会导致结果错误的情况。
顺序重要。 UDP 数据报 2 可能在数据报 1 之前到达。
消息很大。 大的有效载荷必须由应用程序拆分成较小的数据报;传输层不会代劳。如果其中任何一块丢失,整条消息就不完整了。
如果上述任何一种情况适用,请改用 TCP。
9.9.4. 摄像头上的具体示例¶
现实中摄像头一侧的 UDP 流量示例:
发现。 摄像头在启动时向本地网络广播一个“谁在这里”的数据报;其他设备予以回复。
遥测。 摄像头每秒向收集器发送一个携带其当前传感器读数的小数据报。偶尔丢失一个采样并无大碍,因为反正下一个会在一秒内到达。
时间同步。 NTP,即网络时间协议,运行在 UDP 之上。客户端发送一个小请求,服务器以当前时间回复;如果回复丢失,客户端稍后再问一次即可。
DNS 查找。 向网络询问“这个名称映射到哪个 IP?”运行在 UDP 之上。(在 名称与 DNS 中介绍。)
用于发送和接收数据报的 Python API 在 UDP 套接字 中介绍,那时传输层的其余内容已就位。