一、UDP概述
- UDP协议就不过多的介绍了,可以参阅:TCP/IP卷一:54---UDP之(用户数据报协议(UDP)简介、UDP数据报格式、UDP校验和)_udp4784-CSDN博客,或者其他关于UDP的文章
- 下面有一个网站可以来查看当前各国的流量速率比,进入之后找到中国,点击查看:Speedtest Global Index – Internet Speed around the world – Speedtest Global Index
二、UDP的特性与应用场景
- 采用UDP有3个关键点:
- 网络带宽需求较小,而实时性要求高
- 大部分应用无需维持连接
- 需要低功耗
- 应用场景:
- 网页浏览:新浪微博就已经用了QUIC协议
- 流媒体:WebRTC就是基于UDP的
- 实时游戏:Unity3D采用的RakNet也是基于UDP的协议
基于UDP协议的QUIC协议
- QUIC(Quick UDP Internet Connection)是谷歌制定的一种基于UDP的低时延的互联网传输层协议
- 详情可参阅:https://eng.uber.com/employing-quic-protocol/
UDP传输时需要注意的问题
- 数据包确认机制
- 数据包重传机制
- 尽量不发送大于路径MTU的数据包
- 处理数据包重排
三、UDP与MTU
IP分片的概念
- 在TCP/IP分层中,数据链路层用MTU(Maximum Transmission Unit,最大传输单元)来限制所能传输的数据包大小,MTU是指一次传送的数据最大长度,不包括数据链路层数据帧的帧头,如以太网的MTU为1500字节,实际上数据帧的最大长度为1514字节,其中以太网数据帧的帧头为14字节
- 当发送的IP数据包的大小超过了MTU时,IP层就需要对数据进行分片,否则数据将无法发送成功
- IP层是没有超时重传机制的,如果IP层对一个数据包进行了分片,只要有一个分片丢失了,只能依赖于传输层进行重传,结果是所有的分片都要重传一遍,这个代价有点大;公网传输,需要经过多个网络设备,IP分片容易造成丢包
- 由此可见,IP分片会大大降低传输层传送数据的成功率,所以我们要避免IP分片
UDP与MTU的关系
- MTU是指通信协议的链路层上面所能通过的最大数据包大小
- 单个UDP传输的最大内容1472字节,但由于不同的网络中转设备设置的MTU值并不相同:
- Internet环境下:标准MTU值为576字节,UDP的数据长度应该控制在548字节(576-8-20)以内
- 局域网环境下:UDP的数据长度控制在1472个字节以内
四、UDP分包与组包设计
为什么要对UDP进行分包与组包
- 通过上面对MTU的介绍我们知道,如果IP数据包的大小超过了其所在环境中MTU的大小,那么就会对IP数据包进行分片
- 当分片只要其中一个片段丢失,那么就需要重传所有的分片数据,因此这种消耗是比较大的
主要思想
- 在应用层,我们对UDP数据进行传输时调用的两个接口为sendto()和recvfrom()
- 我们将传输的数据(原始数据,可能很大)分割为一个一个小的分片,使分片的大小不大于MTU的大小,这样我们在进行UDP数据传输的时候,就不会产生上面IP分片的问题了
- 对于每一个分片我们需要设计其格式,例如下面是定义的一种格式。相关字段为如下所示
代码
- GIthub链接:https://github.com/dongyusheng/csdn-code/tree/master/udp_piece
- 其中:
- circular_buffer.h/.c:环形缓冲区,用来保存数据的
- udp-piece.h/.c:UDP分片与重组(核心代码)
- udp-piece-client.c:客户端测试代码,代码内会向服务端发送UDP数据
- udp-piece-server.c:服务端测试代码,接收客户端的UDP数据
编码主要思路
- udp-piece.h:
- 定义了如下的宏和结构,主要用来描述分片节点的
- 其中比较重要的一个字段为PIECE_FIX_SIZE,其代表我们分片中实际数据的长度,因为Internet中MTU的大小通常为576,所以我们的UDP数据包最好不要超过576-8-20大小(8为UDP头大小,20位IP报文大小),另外还要减去12(因为我们分片也有头,为12字节)
- udp-piece-client.c:其向服务端发送一长串字符串,在发送之前先调用udp_piece_cut()对整个UDP数据包进行分片,然后逐个发送出去
- udp-piece-server.c:其从客户端接收UDP数据,将接收的数据放到环形缓冲中,然后进行重组
五、附加
- 本文只介绍了“UDP的分包与组包”,并没有涉及到UDP数据包确认、重传等机制,并且代码也只做到了分包与组包
- 关于UDP更深一步的设计,会在后面“KCP”的文章中介绍的哦