TCP/IP 协议族 - UDP 笔记
引言
UDP 是一种无连接、不可靠的运输协议。它除了在 IP 服务的基础上增加了进程到进程的通信,就没什么了。 就是因为如此,它的额外开销也小。
用户数据报
UDP 分组叫做用户数据报。 UDP 长度 = IP 长度 - IP 首部长度
UDP 服务
进程到进程的通信
无连接服务
这意味着 UDP 发送的每一个用户数据报都是独立的,而且没有编号。每一个用户数据报都能走不同的路径。
无连接导致的一个结果就是:使用 UDP 的进程不能发送数据流到 UDP,也不能期望 UDP 把这个数据流分割成多个相互关联的用户数据报。相反,进程的每一个请求都必须足够小,才能装进去。
流量控制
UDP 不提供流量控制。
差错控制
除了检验和之外,UDP 没有其他的差错控制机制,如果接收方检测到出错,就会悄悄丢掉。 它的伪首部协议字段是 17. UDP 可以选择不检验和。 如果不计算检验和,就在发送之前把检验和字段全部填入0。如果发送方决定计算检验和,但恰巧结果也全是0,这种情况下,在该分组发送之前,检验和全变成 1。因为这种情况永远也不会发生。
拥塞控制
UDP 不提供拥塞控制。
封装和解封
当有进程要用 UDP 发送时,它就把报文连同一对套接字地址以及数据的长度传给 UDP。UDP 收到数据后添加一个 UDP 首部,传给 IP。IP 再加上自己的首部,在协议字段使用 17,表示该数据是从 UDP 协议来的,之后给数据链路层,然后给物理层。 解封同理。
排队
下面探讨端口是如何实现的。
客户端
在客户端,当一个进程启动时,就会从操作系统那里请求得到一个端口号。有些实现为每个进程创建一个入队列和出队列。当进程被终止时,队列被销毁。 客户进程在请求中指明源端口号就能把报文送到出队列,然后 UDP 逐个取出报文,交付给 IP。出队列有可能会溢出,如果溢出,草莎紫铜就要求客户进程在继续发送报文之前先等待。
当一个报文到达客户端时,UDP 先要检查一下,看这个用户数据报中的目的端口号所对应的入队列是否已经创建。如果已经创建了,就放到队列末尾,否则就丢弃,请求 ICMP 协议向服务器端发送端口不可达报文。 入队列有可能会溢出。如果溢出,UDP 就丢弃,并发送端口不可达报文。
服务器端
和上面的流程一样。
UDP 和简单协议的比较
就多了一个检验和的差错控制。
UDP 的应用
UDP 的特点
无连接
如果客户应用需要向服务器发送一个简短的请求,并收到一个简短的响应,那么就可以用 UDP。 如果使用面向连接服务,光建立连接和关闭连接就需要至少交换9个分组(7+2),而无连接只需要2个。
例如 DNS。客户需要向服务器发送一个短小的请求,并希望收到服务器的快速响应。这个请求和响应都能被装进一个用户数据报中,所以没有连续不连续的问题。
但是像 SMTP,这样就不能使用 UDP 了。因为可能电子邮件很长,必须要被分割。那么便可能无法排序。
缺少差错控制
比如看视频的时候,一帧损坏了,如果是可靠的服务,它会等这一帧重传。这时候我们就看到白屏了。 而如果用 UDP,它直接丢弃,少这么一帧也没事。不过要对帧进行排序。
缺少拥塞控制
虽然 UDP 缺少拥塞控制,不过 UDP 不会给故障频出的网络带来额外的通信量。
典型应用
- 适用于值要求简单的请求-响应通信的进程。
- 适用于具有内部流量控制和差错控制机制的进程,例如 TFTP。
- 适用于某些路由选择更新协议,如 RIP。
- 适用于某些实时应用。
UDP 软件包
控制块表
UDP 使用控制块表来记录打开的端口,表中每一项至少有四个字段:
- 状态
- 进程 ID
- 端口号
- 队列号
控制块模块
udp_control_block_module(process_id, port_number):
查找控制块表中的 FREE 表项
if 未找到:
使用事先定义的策略删除一个表项
创建状态为 IN-USE 的新表项
输入进程 ID 和端口号
返回
输入模块
udp_input_module(user_datagram):
在控制块中查找相应的表项
if 找到:
检查队列字段,看是否分配了一个队列
if 未分配:
分配一个队列
else:
把数据放入相应队列
else:
请求 ICMP 发送端口不可达报文
丢弃这个数据报
返回
输出模块
负责创建和发送数据报。不写代码了。
- 上一篇 Redis 源码阅读 - 链表
- 下一篇 TCP/IP 协议族 - TCP 笔记