TCP/IP 协议族 - UDP 笔记

Apr 11, 2016


引言

UDP 是一种无连接、不可靠的运输协议。它除了在 IP 服务的基础上增加了进程到进程的通信,就没什么了。 就是因为如此,它的额外开销也小。

用户数据报

UDP 分组叫做用户数据报。 UDP 长度 = IP 长度 - IP 首部长度

UDP 服务

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 发送端口不可达报文
        丢弃这个数据报
    返回

输出模块

负责创建和发送数据报。不写代码了。