本篇将主要介绍 UDP 协议,介绍了有关 UDP 协议的报头、协议特点、UDP 协议在操作系统中的缓冲区、UDP 协议使用的注意事项,以及有关 UDP 的 Socket 编程程序,同时重点介绍了操作系统对于 UDP 协议报文的管理。
接着介绍了有关端口号的映射。
目录
UDP协议
1. UDP协议报头
2. UDP协议特点
3. UDP的缓冲区
4. OS对UDP报文的管理
4. UDP 使用的注意事项
5. 基于UDP的应用层协议
6. 基于UDP协议的程序
端口号的映射
1. 端口号范围划分
2. 端口号与进程的映射
UDP协议
对于 UDP 报文的格式如下:
1. UDP协议报头
对于如上 UDP 报文,分别由 16 位的源端口,目的端口,UDP 长度以及 UDP 校验和组成,这样的一个组成在 Linux 源码其实也已经将其抽象为了一个结构体,如下:
对于 16 位 UDP 长度,表示整个数据报(首部 + 数据)的最大长度;若校验和出错,就会直接将该 UDP 数据包给丢弃。
通过如上的 UDP 报文结构我们也可以得出,若我们想要将报头和有效载荷进行分离,只需要将前 8 个字节截断即可,因为这是固定长度的报头。当需要将数据向应用层进行分用的时候只需要通过 16 位目的端口和进程的映射就可以直接将数据传输上去。
那么我们在接收对应的 UDP 报文数据之后,如何轻易的拿到首部中的四个数据呢?我们只需要使用一个 struct udphdr * 一样的指针接收对应的报文,然后就可以拿出对应的四个首部数据了,通过该方法拿出数据,我们只需要注意网络序列的转化,不用担心在不同的操作系统下不兼容的情况,因为所有的操作需求都是由 C 语言写的。
2. UDP协议特点
UDP 传输协议一共有以下 3 个特点:
无连接:只要知道对方的 IP 和 PORT 就可以直接进行传输,不需要双向进行连接
不可靠:没有数据确认机制,没有数据丢失后的重传机制,如果因为网络故障该段无法发送到对方,UDP 协议层也不会给应用层返回任何的错误信息
面向数据报:不能够灵活的控制读写数据的次数和数量
对于以上的不可靠并不能代表这是 UDP 协议的一个缺点,最好将其认识为 UDP 数据报的一个特点,因为不可靠的同时,带来的是传输速率的提高。
对于面向数据报而言,每一个数据报都是独立的个体,也就是应用层向下发送多大的数据,UDP 就包装多大的数据,并不会将传下来的数据拆分或者合并后在封装(同时,如果在发送端调用 sendto 发送了 100 个字节,那么接收端也必须使用 recvfrom 一次接收 100 个字节的数据,不能分多次来接收)。
3. UDP的缓冲区
UDP 没有真正意义上的缓冲区,当我们调用 sendto 会直接交给内核处理,由内核将数据传给网络层协议进行后续的传输动作。
UDP 具有接收缓冲区,但是这个接收缓冲区并不能保证收到的 UDP 报文的顺序和发送 UDP 报的顺序一致,同时,若接收缓冲区满了,再达到的 UDP 的数据就会被丢弃。
4. OS对UDP报文的管理
我们的传输层是属于操作系统内核中的,同时说明对于 UDP 协议的接收缓冲区也是在 OS 中的,在操作系统中可能有着很多的 UDP 数据报在其中,有的数据报存储在缓冲区中准备向上交付,有的数据报正从上层向下传输,这个时候 OS 中充满了 UDP 数据报,这个时候 OS 就会对其进行管理,使用 struct sk_buff 结构体对 UDP 数据报进行管理,管理方法如下:
在操作系统内会存在一个管理 UDP 数据报的一个结构体 struct sk_buff,同时这个结构体还有一个缓冲区,结构体中的 head 和 data 指针起初都是指向缓冲区的中间,当有数据从应用层向下交付的时候,先将数据拷贝到缓冲区,然后 head 指针向前移动 8 个字节,接着将 UDP 首部的四个数据给填充即可,同时这样的 sk_buff 结构体不止一个,每个结构体之间使用指针相连接,如下:
4. UDP 使用的注意事项
我们在 UDP 报头中有一个 16 位的报文长度,也就是说对于一个 UDP 能传输的数据最大长度为 64K(包含首部)。但是在当今的互联网环境下,64K 的数据是一个很小的数据量,所以当我们需要传输的数据超过 64K 的时候,就需要在应用层将数据手动分包,分多次发送,并在接收端手动拼装。
5. 基于UDP的应用层协议
常见的基于 UDP 协议的应用层协议如下:
NFS: 网络文件系统
TFTP: 简单文件传输协议
DHCP: 动态主机配置协议
BOOTP: 启动协议(用于无盘设备启动)
DNS: 域名解析协议
同时还包括自己写的基于 UDP 协议的程序。
6. 基于UDP协议的程序
如下是一个基于 UDP 协议写的三个程序:UDP/TCP --- Socket编程-CSDN博客https://blog.csdn.net/m0_74830524/article/details/141218715?spm=1001.2014.3001.5501 以上链接便是写的三个程序。
端口号的映射
对于端口号而言,它标识了一个主机上进行通信的不同的应用程序。特别是在 TCP/IP 协议中,用:源 IP + 源端口号 + 目的 IP + 目的端口号 + 协议号 这五元组来标识一个通信,如下:
1. 端口号范围划分
对于端口号而言都是 16 位的一个数据,所以一个端口号的范围为:0 ~ 65535,但是其中也分为知名端口号和普通端口号。如下:
0 - 1023:知名端口号,HTTP、FTP、SSH 等这些广为使用的应用层协议,他们的端口都是固定的
1024 - 65535:操作系统动态分配的端口号,客户端程序的端口号,就是操作系统从这个范围分配的
对于知名端口号而言,我们平时写的程序并不能绑定这些端口号,如下:
当想要绑定知名端口号的时候,就会显示权限不够,只有当使用 root 权限才能绑定知名端口。
其中常见的知名端口号有以下这些:
ssh 服务器:使用22号端口
ftp 服务器:使用21号端口
telnet 服务器:使用23号端口
http 服务器:使用80号端口
https 服务器:使用443号端口
使用命令 cat /etc/services 就可以看见知名端口号:
2. 端口号与进程的映射
一个端口号只可以绑定一个进程,但是一个进程可以绑定多个端口,如下:
如上所示,对于端口号而言其实就像一个已经安排的 hash 表,在表中存储着对应的进程,当传输信息向上传递的时候,找到对应的端口之后就可以直接找到与端口绑定的进程。