UDP的传输方式:面向报文

  面向报文的传输方式决定了UDP的数据发送方式是一份一份的,也就是应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文。那么UDP的报文大小由哪些影响因素呢?UDP数据包的理论长度是多少,合适的UDP数据包应该是多少呢?

(1)UDP报文大小的影响因素,主要有以下3个

[1] UDP协议本身,UDP协议中有16位的UDP报文长度,那么UDP报文长度不能超过2^16=65536.
[2] 以太网(Ethernet)数据帧的长度,数据链路层的MTU(最大传输单元)。
[3] socket的UDP发送缓存区大小

(2)UDP数据包最大长度

sendto函数会错误码1(Operation not permitted, No buffer space available)。

(3)UDP数据包理想长度

以太网转发设备会丢弃这些数据帧。由于以太网EthernetII最大的数据帧是1518字节,除去以太网帧的帧头(DMAC目的MAC地址48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和帧尾CRC校验部分4Bytes那么剩下承载上层协议的地方也就是Data域最大就只能有1500字节这个值我们就把它称之为MTU。
  在下层数据链路层最大传输单元是1500字节的情况下,要想IP层不分包,那么UDP数据包的最大大小应该是1500字节 – IP头(20字节) – UDP头(8字节) = 1472字节。不过鉴于Internet上的标准MTU值为576字节,所以建议在进行Internet的UDP编程时,最好将UDP的数据长度控制在 (576-8-20)548字节以内。

UDP数据包的发送和接收问题

(1) UDP的通信有界性

  在阻塞模式下,UDP的通信是以数据包作为界限的,即使server端的缓冲区再大也要按照client发包的次数来多次接收数据包,server只能一次一次的接收,client发送多少次,server就需接收多少次,即客户端分几次发送过来,服务端就必须按几次接收。

(2) UDP数据包的无序性和非可靠性

  client依次发送1、2、3三个UDP数据包,server端先后调用3次接收函数,可能会依次收到3、2、1次序的数据包,收包可能是1、2、3的任意排列组合,也可能丢失一个或多个数据包。

(3) UDP数据包的接收

  client发送两次UDP数据,第一次 500字节,第二次300字节,server端阻塞模式下接包,第一次recvfrom( 1000 ),收到是 1000,还是500,还是300,还是其他?

由于UDP通信的有界性,接收到只能是500或300,又由于UDP的无序性和非可靠性,接收到可能是300,也可能是500,也可能一直阻塞在recvfrom调用上,直到超时返回(也就是什么也收不到)。

在假定数据包是不丢失并且是按照发送顺序按序到达的情况下,server端阻塞模式下接包,先后三次调用:recvfrom( 200),recvfrom( 1000),recvfrom( 1000),接收情况如何呢?

由于UDP通信的有界性,第一次recvfrom( 200)将接收第一个500字节的数据包,但是因为用户空间buf只有200字节,于是只会返回前面200字节,剩下300字节将丢弃。第二次recvfrom( 1000)将返回300字节,第三次recvfrom( 1000)将会阻塞。

(4) UDP包分片问题

  如果MTU是1500,Client发送一个8000字节大小的UDP包,那么Server端阻塞模式下接包,在不丢包的情况下,recvfrom(9000)是收到1500,还是8000。如果某个IP分片丢失了,recvfrom(9000),又返回什么呢?
  根据UDP通信的有界性,在buf足够大的情况下,接收到的一定是一个完整的数据包,UDP数据在下层的分片和组片问题由IP层来处理,提交到UDP传输层一定是一个完整的UDP包,那么recvfrom(9000)将返回8000。如果某个IP分片丢失,udp里有个CRC检验,如果包不完整就会丢弃,也不会通知是否接收成功,所以UDP是不可靠的传输协议,那么recvfrom(9000)将阻塞。

UDP丢包问题

  在不考虑UDP下层IP层的分片丢失,CRC检验包不完整的情况下,造成UDP丢包的因素有哪些呢?

socket缓冲区满造成的UDP丢包

  通过 cat /proc/sys/net/core/rmem_default 和cat /proc/sys/net/core/rmem_max可以查看socket缓冲区的缺省值和最大值。如果socket缓冲区满了,应用程序没来得及处理在缓冲区中的UDP包,那么后续来的UDP包会被内核丢弃,造成丢包。在socket缓冲区满造成丢包的情况下,可以通过增大缓冲区的方法来缓解UDP丢包问题。但是,如果服务已经过载了,简单的增大缓冲区并不能解决问题,反而会造成滚雪球效应,造成请求全部超时,服务不可用。

  [2] UDP socket缓冲区过小造成的UDP丢包

  如果Client发送的UDP报文很大,而socket缓冲区过小无法容下该UDP报文,那么该报文就会丢失。

  [3] ARP缓存过期导致UDP丢包

arp_queue这个队列中,默认最多缓存3个包,多余的UDP包会被丢弃。被丢弃的UDP包可以从/proc/net/stat/arp_cache的最后一列的unresolved_discards看到。当然我们可以通过echo 30 > /proc/sys/net/ipv4/neigh/eth1/unres_qlen来增大可以缓存的UDP包。

  UDP的丢包信息可以从cat /proc/net/udp 的最后一列drops中得到,而倒数第四列inode是丢失UDP数据包的socket的全局唯一的虚拟i节点号,可以通过这个inode号结合lsof(lsof -P -n | grep 25445445)来查到具体的进程。

UDP冗余传输

  在外网通信链路不稳定的情况下,有什么办法可以降低UDP的丢包率呢?一个简单的办法来采用冗余传输的方式。如下图,一般采用较多的是延时双发,双发指的是将原本单发的前后连续的两个包合并成一个大包发送,这样发送的数据量是原来的两倍。这种方式提高丢包率的原理比较简单,例如本例的冗余发包方式,在偶数包全丢的情况下,依然能够还原出完整的数据,也就是在这种情况下,50%的丢包率,依然能够达到100%的数据接收。

UDP 分析

UDP真的比TCP要高效吗

  相信很多同学都认为UDP无连接,无需重传和处理确认,UDP比较高效。然而UDP在大多情况下并不一定比TCP高效,TCP发展至今天,为了适应各种复杂的网络环境,其算法已经非常丰富,协议本身经过了很多优化,如果能够合理配置TCP的各种参数选项,那么在多数的网络环境下TCP是要比UDP更高效的。

  影响UDP高效因素

(1)无法智能利用空闲带宽导致资源利用率低

吞吐量之间达到一个很好的平衡。

(2)无法动态调整发包

拥塞控制,这样在网络出现拥塞或通信两端处理能力不匹配的时候,UDP并不会进行调整发送速率,从而导致大量丢包。在丢包的时候,不合理的简单重传策略会导致重传风暴,进一步加剧网络的拥塞,从而导致丢包率雪上加霜。更加严重的是,UDP的无秩序性和自私性,一个疯狂的UDP程序可能会导致这个网络的拥塞,挤压其他程序的流量带宽,导致所有业务质量都下降。

(3)改进UDP的成本较高

  可能有同学想到针对UDP的一些缺点,在用户态做些调整改进,添加上简单的重传和动态发包大小优化。然而,这样的改进并比简单的,UDP编程可是比TCP要难不少的,考虑到改造成本,为什么不直接用TCP呢?当然可以拿开源的一些实现来抄一下(例如:libjingle),或者拥抱一下Google的QUIC协议,然而,这些都需要不少成本的。

UDP的使用场合

(1)通信实时性和持续性

  在分组交换通信当中,协议栈的成本主要表现在以下两方面:

[1] 封装带来的空间复杂度[2] 缓存带来的时间复杂度

  以上两者是对立影响的,如果想减少封装消耗,那么就必须缓存用户数据到一定量在一次性封装发送出去,这样每个协议包的有效载荷将达到最大化,这无疑是节省了带宽空间,带宽利用率较高,但是延时增大了。如果想降低延时,那么就需要将用户数据立马封装发出去,这样显然会造成消耗更多的协议头等消耗,浪费带宽空间。

内核缓存延后发送出去,这样时间同步就会出现比较大的偏差,协议将不可用。

(2)多点通信

组播地址发送数据或者轮转地向多个目的地持续发送相同的数据,从而更为容易实现多点通信。)

  一个典型的场景是多人实时音视频通信,这种场景下实时性要求比较高,可以容忍一定的丢包率。比如:对于音频,对端连续发送p1、p2、p3三个包,另一端收到了p1和p3,在没收到p2的保持p1的最后一个音(也是为什么有时候网络丢包就会听到嗞嗞嗞嗞嗞嗞…或者卟卟卟卟卟卟卟卟…重音的原因),等到到p3就接着播p3了,不需要也不能补帧,一补就越来越大的延时。对于这样的场景就比较合适用UDP了,如果采用TCP,那么在出现丢包的时候,就可能会出现比较大的延时。

UDP使用原则

通常情况下,UDP的使用范围是较小的,在以下的场景下,使用UDP才是明智的

  • 实时性要求很高,并且几乎不能容忍重传,例子:NTP协议,实时音视频通信,多人动作类游戏中人物动作、位置
  • TCP实在不方便实现多点传输的情况
  •  )
  • 对网络状态很熟悉,确保udp网络中没有氓流行为,疯狂抢带宽
  • 熟悉UDP编程

 

相关文章:

  • 2022-12-23
  • 2021-11-17
  • 2021-05-29
  • 2021-06-06
  • 2021-10-10
  • 2021-12-19
  • 2022-01-11
猜你喜欢
  • 2021-07-13
  • 2021-07-26
  • 2021-11-19
  • 2021-06-18
  • 2021-11-25
  • 2021-11-14
  • 2021-12-29
相关资源
相似解决方案