我听说过UDP之UDP的特点


  在学习网络编程的过程中,都是从 socketbindlistenaccept这一套组合拳开始的,绝大多数都很了解TCP的种种特性,但对UDP了解甚微,甚至从未写过UDP网络编程的代码。

​   回看谢希仁的《计算机网络第七版》,仅仅花了一页半介绍UDP,而《TCP/IP协议族第四版》却花了整整一章介绍UDP的种种特性。

​ 那我们就从UDP到底做了什么开始聊起。

UDP功能

在这里插入图片描述

​   上图为UDP的头部格式,其实从头部数据可以看出,UDP实现的功能并不多。没有了TCP的各种序列号、窗口值以及标志位等数据,UDP似乎只实现传输层该有的极为简单的功能。所以谢希仁如此写到:

用户数据报协议UDP旨在IP的数据报服务之上增加了很少一点的功能,这就是复用和分用的功能以及差错检测的功能。

​   同样在《TCP/IP协议族》中也能找到类似的话:

它除了在IP服务的基础上增加了进程到进程的通信,使之不再是主机到主机的通信之外,就再没什么了。

​ 我们先简单看看UDP报文头中的每个字段的意义。

源端口

​   这是在源主机上运行的进程所使用的的端口号,它有16位长,也就是表示范围为(0~65535)。在不需要时次字段全为0。

目的端口

​   这是运行在目的主机上的进程所使用的的端口号,它也是16位长。在终点交付报文时必须使用。

长度

​   这也是一个16位的字段,它定义了用户数据报的长度(UDP首部长度+UDP数据长度),单位为字节。

​   至于这个长度字段的范围,UDP首部大小固定为8字节,所以这个长度字段的最小值就是8字节。但对于最大值,却达不到65535:别忘了UDP用户数据报要放在总长度为65535字节的IP数据包中,所以UDP首部的大小字段最大值仅可能为65535减去IP数据包首部大小。

​   对于这一长度字段,《TCP/IP协议族第四版》中还有这样一段话:

​ UDP用户数据包中的长度字段实际上不是必要的。用户数据报被封装在一个IP数据报中。在IP数据报中有一个字段定义了总长度,另外还有一个字段定义了首部的长度。因此如果我们吧第一个字段的值减去第二个字段的值,就可以推导出封装在IP数据包中的UDP数据报的长度。

​ 但是,UDP协议的设计者认为,让终点的UDP直接从UDP用户数据报中提供的信息来计算数据长度,要比请求IP软件来提供这一信息效率更高。我们应当记得,当IP软件吧UDP用户数据报交付给UDP层时,它已经剥去了IP首部。

校验和

​   这个字段用来检测种鸽用户数据报出现的差错,在计算校验和的过程中,要在UDP用户数据报之前添加12个字节的伪首部。伪首部中包括源IP地址、目的IP地址以及其它信息。值得注意的是这个伪首部既不向下层传递也不向上层递交,仅仅是用来计算校验和,具体的计算方法可见这篇博文:

https://www.cnblogs.com/limanjihe/p/10177195.html

​   但值得注意的一点是:UDP分组的发送方可以选择不计算校验和,若不计算校验和,则在发送之前把校验和字段全部填入0。而如果发送方选择计算校验和,且碰巧得到的结构也全是0,在这种情况下,在该分组发送之前检验和变成全1。因为在正常情况下计算出的校验和的值永远不可能全为1,因此不会导致混淆。


​ 那UDP去繁就简之后,我们就从它和TCP的区别入手,介绍UDP的一些特性。

UDP VS TCP

无连接 VS 有连接

​   这应该是大家听到UDP后的第一个反应了:UDP是一种无连接、不可靠的运输协议的。

​   这意味着每隔一用户数据报都是独立的数据包,不同的用户数据报之间没有任何关系,哪怕它们是来自相同的源进程并且去往相同的目的程序。

​   无连接导致的一个结果就是:使用UDP的进程不能期望UDP把这个数据流分割成为许多个相互关联的用户数据报。相反,进程的每一个请求都必须足够小,使其能够装进一个用户数据报中。(实际情况不仅要考虑IP数据包的最大长度,更重要的是考虑链路层MTU的大小)。

流量控制:NO VS YES

​   UDP去繁就简,当然没有流量控制这种复杂的东西,没有窗口机制,这导致接收方可能会因为入口的报文太多而溢出(接收方端口队列的报文过多,下文将提及)。

​   但这一机制带来的另一方面的效果就是网络出现拥塞时不会使源主机的发送速率降低,而这一特性对于实时应用是很重要的。很多的实时应用(视频会议、直播等)要求源主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但却不允许数据有太大的时延。UDP正好适合这种要求。

面向报文 VS 面向字节流

​   在TCP中,没有“包长度”字段,而完全依靠IP层去处理分帧,这就是为什么TCP常常被称为一种“流协议”的原因:开发者在使用TCP服务的时候,不必去关心数据包的大小,只需要将SOCKET看做一条数据流的入口,往里面放数据就行了。

​   而在UDP中,发送方的UDP对应用程序叫下来的报文,在添加首部后就向下交付IP层。UDP对应用叫下来的报文,既不合并,也不拆分,而是保留这些报文的边界。这就是说应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文,但如上文提到,用户必须选择UDP报文的大小:

  • 若报文太长,UDP把它交给IP层之后,IP层在传送时可能要进行分片,这会降低IP层的效率。
  • 若报文太短,UDP把它交给IP层后,会使IP数据报的首部的相对长度太大,这也降低了IP层的效率。

差错控制:NO VS YES

​   TCP通过SEQ NUM、ACK NUM、超时重传机制等提供差错控制机制,而UDP不提供差错控制。这就表示发送方并不知道报文是丢失了还是重复交付了:当接收方通过校验和检测出差错时,就悄悄将这个用户数据报丢掉。

双工性:一对多、一对一、多对一、多对多 VS 全双工

​   TCP的通信为全双工通信,而UDP支持的是一对多、一对一、多对一、多对多的交互通信。

UDP其它特性

队列机制

在这里插入图片描述

客户端

​   在客户端,当一个进程启动时,它从操作系统那里请求得到一个端口号,并且最终得的一个出的和一个入的队列,客户进程在请求中指明源端口号就可以把报文送到出队列。UDP逐个把报文取出,先添加UDP首部,再交付给IP。出队列若发生溢出,操作系统将要求客户进程在继续发送报文之前先等待。

​   当一个报文到达客户端时,UDP首先要检查一下这个用户数据报中的目的端口号字段指明的端口号所对应的入队列是否已创建。若已经有了这样的队列,UDP就把收到的用户数据报放在该队列的末尾。**若没有这样的队列,UDP就丢弃这个用户数据报,并请求ICMP协议向服务器发送端口不可达报文。**所有发送给某个特定客户程序的入报文,不管是偶不是来自相同的或者是不同的服务器,都被放入同一个队列中。队列有可能会溢出,若发生溢出,UDP就丢弃这个用户数据报,并请求向服务器发送一个ICMP端口不可达报文。

服务端

​   在服务端,创建队列的机制是不同的,在最简单的形式下,服务器进程在它开始运行时就请求为它的熟知端口创建入队列和出队列。只要服务器进程在运行,这些队列就一直是打开的。

​   当报文到达服务器进程时,UDP首先检查这个用户数据报中的目的端口号字段指明的端口号所对应的入队列是否已创建。若已有这样的队列,UDP就把收到的用户数据报放在这个队列的末尾。**若没有这样的队列,同样请求ICMP协议发送端口不可达报文。**所有发送给特定服务器的如报文,不管是来自相同的或者是不同的客户端,都被放入同一个队列。入队列若溢出,UDP将丢弃这个用户数据报,并发送端口不可达。

​   服务器想要回答客户时,操作和客户端基本一致。

UDP典型应用

  下面出的是使用UDP的服务要比使用TCP的服务收益更大的典型应用:

  • UDP适用于只要求简单的请求-响应通信的进程,它们很少会考虑流量控制和差错控制。但对于需要传送大量数据的进程,通常不使用UDP
  • UDP适用于具有内部流量控制和差错控制机制的进程,例如简单文件传送协议(TFTP)的进程就包括流量控制和差错控制。他能够很容易使用UDP。
  • 对多播来说,UDP是个合适的传输层协议。
  • UDP适用于管理进程,如SNMP
  • UDP适用于某些路由选择更新协议,如RIP
  • UDP通常适用于实时应用,它们不能容忍在接收报文的各个片段之间存在变化的时延

以下知名应用用的都是UDP:

  • DNS
  • DHCP
  • OpenSSL
  • OpenVPN
  • QUIC
  • KCP
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值