UDP 分片 与 丢包,UDP 真的比 TCP 高效吗?UDP 的应用场景

目录

一、UDP 报文格式

二、UDP 分片

1、UDP 有发送缓存区吗?

1>、先说结论:

2>、逐步分析:

2、UDP 分片

1>、UDP 包最佳传输大小

2>、分片问题

三、UDP 丢包的原因

1、UDP 缓冲区满,造成的丢包

2、UDP 缓冲区过小或文件过大,造成的丢包:

3、ARP 缓存过期,导致丢包:

4、接收端处理时间过长导致丢包:

5、发送的包巨大丢包:

6、发送的包频率太快:

7、局域网内不丢包,公网上丢包。

四、UDP 丢包的解决方案

1. 从发送端解决 - 延迟发送

2.从接收端解决:数据接收 与 数据处理相分离

3.从接收端解决:修改接收缓存大小

五、UDP 实现对方百分百收到数据

1、UDP 致命性缺点:

2、解决方案 - 回复 + 重发 + 编号 机制:

1>、分析:

2>、回复 + 重发 + 编号 机制

3、解决方案 - 冗余传输方案:

4、解决方案 - RUDP:

六、UDP 真的比 TCP 要高效吗

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

2、无法动态调整发包:

3、改进 UDP 的成本较高:

七、UDP 协议的正确使用场合

1、高通信 实时性要求 和 低持续性要求 的场景下

2、多点通信的场景下

3、UDP应用举例

4、QQ udp 浅析

1>、用 tcp 长连接,对服务器的负担很大

2>、tcp 较难实现 NAT 穿越

3>、让 UDP 变得可靠


一、UDP 报文格式

每个 UDP 报文分为 UDP 报头和 UDP 数据区两部分。报头由 4 个 16 位长(2 字节)字段组成,分别说明该报文的源端口、目的端口、报文长度和校验值。

UDP 报文格式如图所示。

UDP 报文中每个字段的含义如下:

  • 源端口:     16bits,发送端的端口。
  • 目的端口: 16bits,即接收端的端口
  • 长度:         16bits,UDP 数据包总的大小:包头+数据,单位:字节。
  • 校验值:      16bits,错误检查码,基于算法,计算此 UDP 数据包是否损坏

二、UDP 分片

1、UDP 有发送缓存区吗?

TCP 有 发送/接收 缓存区,那 UDP 有么?

1>、先说结论:

每个 UDP socket 都有一个接收缓冲区没有发送缓冲区,从概念上来说就是只要有数据就发,不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区。

UDP:当套接口接收缓冲区满时,新来的数据报无法进入接收缓冲区,此数据报就被丢弃。UDP是没有流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的 UDP 丢弃数据报。

且,如果在传输过程中,一次传输被分成多个分片,传输中有一个小分片丢失,那接收端最终会舍弃整个文件,导致传输失败,这就是 UDP 不可靠的原因。

2>、逐步分析:

linux手册中有设置 UDP 发送缓冲区相关属性,也明确提到了send buffer的概念:

   那这是否意味着 UDP 是有发送缓冲区的吗?我们再看一下《UNIX Network Programming》书中所述,这本书的作者权威性我就不多说了吧,在国内高校此书都是当做教材使用的。书中有下面两幅图:

一张是 TCP 发送过程协议栈简化图,另一张是 UDP 的。UDP 中的 send buffer 是用虚线框圈起来的,具体的叙述我直接引用书中原文:

   书中的描述很清楚了,UDP 是没有发送缓冲区的,因为 UDP 是不可靠的,他不必像 TCP 一样需要一个实质的发送buffer,而且真正 UDP 写成功返回其实是传递到了链路层的 output queue 中。

2、UDP 分片

1>、UDP 包最佳传输大小

数据链路层 最大传输单元是 1500 字节 (MTU) ,要想 IP 层不分包,那么 UDP 数据包的最大大小应该是1500字节 – IP头(20字节) – UDP头(8字节) = 1472字节

但,理论上 UDP 报文最大长度是 65507 字节,那:实际上发送这么大的数据包效果最好吗?

我们来看分析一下 “分片问题”

关于 UDP 包大小、MTU相关知识,可以参照上一篇文章:

最大可传输单元 MTU 对 UDP/TCP 包的大小限制_LearnLHC的博客-CSDN博客_mtu udp

2>、分片问题

我们知道 UDP 是不可靠的传输协议,为了减少 UDP 包丢失的风险,我们最好能控制 UDP 包在 IP层协议的传输过程中不要被切割。

这是为什么呢?

如果 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) 将阻塞。

分片分的越多,虽然在传输层都是一次 send,一次 recv ,但在传输过程中,会传输多次,那么丢包的概论就越大,如何解决丢包问题呢?

三、UDP 丢包的原因

前提:

在不考虑 IP 层的分片丢失,CRC 检验包不完整的情况下

1、UDP 缓冲区满,造成的丢包

如果 socke t缓冲区满了,应用程序没来得及处理在缓冲区中的 UDP 包,那么后续来的 UDP 包会被内核丢弃,造成丢包。

在 socket 缓冲区满造成丢包的情况下,可以通过增大缓冲区的方法来缓解UDP丢包问题。但是,如果服务已经过载了,简单的增大缓冲区并不能解决问题,反而会造成滚雪球效应,造成请求全部超时,服务不可用。

2、UDP 缓冲区过小或文件过大,造成的丢包:

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

以前遇到过这种问题,我把接收缓冲设置成 64K 就解决了。

int nRecvBuf=32*1024;//设置为32K

setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

3、ARP 缓存过期,导致丢包:

ARP 的缓存时间约 10 分钟,APR 缓存列表没有对方的 MAC 地址或缓存过期的时候,会发送 ARP 请求获取 MAC 地址,

在没有获取到 MAC 地址之前,用户发送出去的 UDP 数据包会被内核缓存到 arp_queue 这个队列中,默认最多缓存 3 个包,多余的 UDP 包会被丢弃。

4、接收端处理时间过长导致丢包:

调用 recv 方法接收端收到数据后,处理数据花了一些时间,处理完后再次调用 recv 方法,在这二次调用间隔里,发过来的包可能丢失。

对于这种情况可以修改接收端,将包接收后存入一个缓冲区,然后迅速返回继续 recv。

5、发送的包巨大丢包:

虽然 send 方法会帮你做大包切割成小包发送的事情,但包太大也不行。

例如超过 50K 的一个 udp 包,不切割直接通过send 方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个 send。

6、发送的包频率太快:

虽然每个包的大小都小于 mtu size 但是频率太快,例如 40 多个 mut size 的包连续发送中间不 sleep,也有可能导致丢包。

这种情况也有时可以通过设置 socket 接收缓冲解决,但有时解决不了。

所以在发送频率过快的时候还是考虑

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值