伯阳的网络笔记:UDP & IP
0. 前言
UDP 单独拿出来讲,其实内容不算特别多,所以这一篇我干脆把 IP 的一些基础内容也放进来一起看。
对于一个 iOS 开发者来说,IP 协议已经算是非常底层了,不一定需要背得特别细,但至少要知道:
UDP到底比TCP少了什么;UDP在IP之上到底只加了哪些最基本的信息;IP层又负责哪些更底层的事情。
1. UDP 是何物?
UDP(User Datagram Protocol,用户数据报协议)是一个传输层协议,在 RFC 768 中定义。
它提供的是一种按消息为单位的、不可靠的传输服务。也就是说:
- 它能把一份完整消息发出去;
- 但它不保证一定送达;
- 也不保证按顺序送达;
- 更不会像
TCP那样帮你重传、排队、去重。
除了复用功能以及少量差错检测之外,它几乎没有在 IP 之上增加太多东西。所以很多时候,使用 UDP 的感觉,其实已经差不多是在直接和 IP 打交道了。
这里顺便说一下“数据报”这个词:
- 数据报(Datagram)
- 一个完整、独立的数据实体;
- 自己携带从源到目的地所需的基本信息;
- 不依赖之前或之后的数据交换状态。
2. UDP 的特点
UDP 的特点,不在于它额外引入了多少复杂机制,而恰恰在于它主动省略了很多 TCP 拥有的能力。
- 无需建立连接
TCP在发送数据前需要三次握手;UDP则可以直接发。
- 无连接状态
- 不需要长期维护连接状态;
- 更适合一些短消息、流媒体、语音、游戏这类对时延更敏感的场景。
- 首部开销小
UDP首部很短;- 协议处理逻辑也更简单。
- 时延更低
- 没有握手带来的启动成本;
- 也没有
TCP那种重传、拥塞控制、按序交付的额外等待。
UDP 在 IP 之上只加了什么
这个要从 IP 协议说起。
IP 协议的主要任务,是按照地址把数据报从源主机送到目标主机。为此,消息会先被封装进一个 IP 分组,里面至少要写清楚源地址、目标地址,以及一些路由和分片相关的控制信息。
而 UDP 在 IP 之上做的事情其实很少:它只额外增加了一层很薄的首部,核心就是下面这几个字段:
| 字段 | 作用 |
|---|---|
| 源端口 | 发送方进程的端口号。IPv4 中可以为 0,表示未使用。 |
| 目的端口 | 接收方进程的端口号。 |
| 长度 | UDP 首部 + UDP 数据的总长度。 |
| 校验和 | 用于校验 UDP 首部、数据以及伪首部。 |
这几个字段的作用分别可以理解成:
- 源端口
- 发送方进程的端口号;
- 某些场景下接收方可以根据它回消息;
- 但它并不是绝对必须的。
- 目的端口
- 数据最终要交给目标主机上的哪个进程;
- 这是 UDP 复用能力里最关键的字段。
- 长度
- 表示整个 UDP 报文的大小;
- 包括 UDP 首部和数据本身。
- 校验和
- 用于校验 UDP 首部、数据,以及伪首部中的相关信息;
- 这是端到端意义上的校验,和 IP 头部自己的校验不是一回事。
这里需要特别强调一个很容易说错的点:
- IPv4 头部确实自带校验和;
- 但这个校验和只覆盖 IP 头部本身;
- 它并不能替代 UDP 对自身首部和数据的校验。
所以不能简单说“IP 自己有校验码,UDP 可以直接用”。这是两层不同的事情。
另外再补一句:
- 在 IPv4 里,UDP 校验和可以为
0,表示发送方没有计算; - 但在 IPv6 里,UDP 校验和一般不能省略。
UDP 的消息边界
TCP 是字节流协议,它不保留应用层消息边界;而 UDP 不一样,它保留的是报文边界。
也就是说:
- 应用层发出去的一次
sendto,对接收方来说就是一份完整消息; - 接收方要么拿到完整的一份 UDP 报文;
- 要么这份报文直接丢失;
- 不会像
TCP那样把一条消息拆成多个有序片段再交给你重组。
但这里也要注意一个容易误解的点:
UDP保留消息边界,不等于 “UDP 数据报在网络层绝对不会被分片”。
实际上:
UDP本身不负责分段、重传、排序和重组;- 但它承载的数据在经过
IP层传输时,仍然可能被IP层分片; - 只是对应用层来说,最终交付单位依然是一份完整 UDP 报文,而不是一个字节流。
3. IP
IP(Internet Protocol,网际协议)是网络层协议。它最核心的任务很简单:
- 给数据报寻址;
- 决定数据往哪里走;
- 尽力把它送到目标主机。
IP 是无连接的
IP 是面向无连接的。
也就是说,在发送数据之前,它不需要像 TCP 那样先和目标建立连接。它看到的只是一个个独立的分组,然后尽力转发。
这也决定了 IP 本身的风格:
- 不保证可靠送达;
- 不保证按序;
- 不保证不重复;
- 更不关心“这是第几次通信”。
这些事情,如果上层需要,就交给 TCP 这种协议自己去补。
4. IPv4 & IPv6
IPv4 地址长度是 32 位;随着互联网规模越来越大,地址逐渐不够用了,于是就有了 IPv6。
IPv6 地址长度是 128 位,也就是 IPv4 的 4 倍。
这两者除了地址长度不一样之外,首部设计思路也有变化。简单对比如下:
| 项目 | IPv4 | IPv6 |
|---|---|---|
| 地址长度 | 32 位 | 128 位 |
| 首部长度 | 可变,最少 20 字节 | 固定 40 字节 |
| 头部校验和 | 有 | 没有 |
| 分片方式 | 路由器和主机都可能参与 | 主要由源主机负责,使用扩展头 |
| 扩展能力 | 依赖选项字段 | 使用扩展头机制 |
如果只从学习角度记,我觉得最值得记住的是这几件事:
IPv6不只是“地址更长”;- 它也顺手把很多旧设计重新整理了,比如首部固定长度、去掉头部校验和、改进扩展能力;
- 从现代网络演进方向来看,
IPv6显然更适合继续扩展。
这里就不继续把每个字段都展开了,有兴趣的话可以继续翻《图解 TCP/IP》或者直接看相关 RFC。
5. 小结
如果把这一篇压缩成几句话,我觉得可以这么记:
UDP是一个非常薄的传输层协议;- 它在
IP之上只增加了最基本的端口、长度和校验能力; - 它保留消息边界,但不提供
TCP那种可靠、有序、可重传的字节流语义; IP则更底层,只负责寻址和转发,不保证可靠性;IPv6不只是地址变长,而是对整个 IP 首部设计做了一次更现代化的整理。
资料
《图解 TCP/IP》