UDP 用户数据报协议
引言
UDP是一种保留消息边界(不合并,不拆分)的简单的面向数据报的传输层协议。使用UDP协议的时候,一般来说,每个被应用程序请求的UDP输出操作只生产一个UDP数据报,并组装成一份待发送的IP数据报(与面向数据流的协议不同,如TCP,应用程序写入的数据与真正在单个IP数据报里传送的内容可能没有什么联系)。UDP不提供差错纠正、队列管理、重复消除、流量控制和拥塞控制,只提供差错校验(校验和)。(注:对于UDP网上有各种各样的描述,但是我个人觉得对UDP描述最到位的还是UDP自己的正式规范,也就是**[RFC0768]**)
前面提到:
- UDP不提供差错纠正、队列管理、重复消除意味着UDP不提供可靠性:它吧应用程序传给IP层的数据发出去,但是不能够保证它们能够到达目的地。
- UDP不提供流量控制和拥塞控制意味着UDP不提供保护性:没有协议机制防止高速UDP流量对其他网路用户的消极影响。
但是凡事总有两面性,[RFC0768]中明确提到"This protocol provides a procedure for application programs to send messages to other programs with a minimum of protocol mechanism",作为minimum的协议,自然UDP是没有那么多花里胡哨的内容。由于UDP相比TCP等协议更“轻”,无连接特征,所以UDP的开销更小,速度更快。
下面画出了一个UDP数据报作为单个IPv4数据报的封装。IPv4中Protocol字段(IPv6是Next Header)用值17标识UDP。值得一提的是,在使用UDP的时候,我们还是需要对IP数据报的长度进行关注,应为如果超过了MTU的时候,那么就会对IP数据报进行分片,这个我们下面会详细聊这个问题。
|<-------- UDP数据报 -------------->|
+--------+--------+----------+------------------------+
| IPv4头部 | UDP头部 | UDP数据 |
| 20字节,不带IP选项 | 8字节 | |
+--------+--------+----------+------------------------+
|<-------------------- IPv4数据报 -------------------->|
UDP头部
首先我们来看一下包含负载和UDP头部的UDP数据报。
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
+--------+--------+--------+--------+
|
| data octets ...
+---------------- ...
端口号(Port)的作用是帮助协议辨认发送和接收的进程。这两个端口号是纯抽象的,不与主机上任何物理实体相关。在图中可以看出,在UDP中两个端口号都是正的16比特的数字。源端口号(Source Port)是可选的,如果数据报的发送者不要求对方回复的话,这里可以直接置成零。目标端口号(Destination Port)的作用是帮助啊分离从IP层进入的数据。IP层会根据IP协议中头部的标识分离到特定的传输协议,也就是说端口号在不同的传输协议之间是独立的。这样导致一个直接结果就是两个完全不同的服务器可以使用相同的端口号和IP地址,只要他们使用不同的传输协议。
长度(Length)字段是UDP头部和UDP数据的总长度,以字节为单位。这个字段的最小值是8。
本来这个长度字段是没啥可说的,但是网上对于这个字段是否冗余以及为什么要设计这个字段却众说纷纭。因为不管是IPv4还是IPv6,在网络层其实都是可以通过“IP总长度 - IP Header长度 - UDP Header长度”计算出Length的值。而且在《TCP/IP详解 卷1:协议》中,也明确提到“**This UDP length is redundant**” UDP长度字段是冗余的。 首先关于该字段是否冗余,基本上在UDP的下层是IP的时候,大家都认为这个字段是冗余的,当然也有人觉得处理UDP的时候还要去读IP的字段会导致“违反分层 layering violation”(我个人不是很认可后者,因为后面提到的UDP伪头部其实整个都是从网络层复制过来的,这个是明显导致“违反分层 layering violation”的,但是UDP设计的时候还是这么设计了,就证明在设计网络协议的时候,如果没有对协议实现产生较大影响,“分层”这个思想其实是可以灵活看待的)。 其次是为什么会设计这个字段,我看了之后觉得比较有可能的几种说法分别是:1.网络层可能不是IP协议,其他协议不一定能计算出Length字段。2.UDP报头设计时发现有一些空间多余,为了方便处理,遵守“协议分层”的思想。3.有可能是UDP和IP协议并行发展的结果,UDP并不是等IP完全占领主导地位之后才开发的协议。 不管是在知乎还是stackoverflow基本上就是上面总结的三种说法,如果问我的话,其实我更倾向于“留着先,有可能