UDP协议原理
本篇介绍
在前面使用UDP编程时已经基本了解了UDP的工作模式,也知道了UDP有三个特点:
- 无连接
- 不可靠
- 面向数据报
但是当时并没有具体谈论为什么UDP有以上三个特点,基于这个原因,本篇就会针对这三个原因进行介绍
UDP协议在底层的设计
前面多次提交,协议本质可以理解为一个结构体,所以UDP协议也是一个含有一些字段的结构体,基本示意图如下:
在上面的结构中,首先是源端口和目的端口,因为UDP属于传输层协议,该层上一层就是应用层,如果上一步是解包,那么接下来的工作就是分用,所以为了知道将接收到的数据具体传输到哪一个应用就需要通过目的端口号进行匹配
在UDP编程接口基本使用提到,端口号port
的类型为uint16_t
,在Linux底层是unsigned short int
,这个类型是两个字节,对应的就是UDP协议结构中一个端口号占用空间的大小
接着就是16位大小的数据长度空间,这个部分主要存储了数据部分内容的长度,具体会在下一部分讲解到
最后就是16位校验和,这个字段用于检测数据在传输过程中是否发生错误,不具体介绍
UDP面向数据报
在前面学习UDP和TCP通信过程中,提到了UDP一般不会出现数据不完整的情况,但是TCP会出现数据不完整的情况所以需要做数据完整性检查,之所以会出现这个原因就是因为UDP是面向数据报的,而TCP是面向字节流的,那么既然UDP是面向数据报,那么在发送或者接收时都必须遵循完整发完整收,这就导致一个问题,客户端和服务端怎么主调这个数据是完整的,在前面TCP编程的封装协议中,都涉及到一个字段「数据长度」,通过数据长度判断是否拿到完整的数据,UDP也不例外,在UDP协议中的16位大小的数据长度字段就是用来指明发送的数据有多大
但是因为这个长度字段只有16位,这就导致了其只能存储64K()的值,也就是说,这个长度是有限的,如果需要传输大于16位2进制可以表示的范围,那么此时就需要对数据进行手动拆分,因为UDP必须满足发多少收多少
UDP无连接
本质上是因为建立连接需要一定的时间和消耗,在TCP中,TCP的建立连接需要至少1.5个RTT(Round-Trip Time)的延迟,所以为了在一些需要效率并且又可以容忍一小部分数据丢失的情况下(例如视频通话)就可以考虑使用UDP
UDP不可靠
因为UDP需要保证效率,在传送的过程中不会对数据进行校验,并且也不会对丢失的内容进行重传,这就导致了丢失的数据无法再次获取。另外,因为UDP没有真正意义上的 发送缓冲区,所以调用sendto
会直接交给内核,再由内核将数据传给网络层协议进行后续的传输动作,但是UDP具有接收缓冲区,不过这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致,如果缓冲区满了,再到达的UDP数据就会被丢弃
基于UDP的应用层协议
常见的有下面几种:
- NFS:网络文件系统
- TFTP:简单文件传输协议
- DHCP:动态主机配置协议
- BOOTP:启动协议(用于无盘设备启动)
- DNS:域名解析协议