UDP协议
一、传输层
我们以前在学习HTTP等应用层协议时,为了便于理解,简单的认为HTTP协议是将请求和响应直接发送到了网络当中。但实际进行网络传输时数据要从应用层先将数据交给传输层,由传输层对数据做进一步处理后再将数据继续向下进行交付,该过程贯穿整个网络协议栈,最终才能将数据发送到网络当中。
传输层负责可靠性传输,确保数据能够可靠地传送到目标地址。为了方便理解,在学习传输层协议时也可以简单的认为传输层协议是将数据直接发送到了网络当中。
1、再谈端口号
端口号(Port)标识一个主机上进行网络通信的不同的应用程序。当主机从网络中获取到数据后,需要自底向上进行数据的交付,而这个数据最终应该交给上层的哪个应用处理程序,就是由该数据当中的目的端口号来决定的。
因此端口号是属于传输层的概念的,在传输层协议的报头当中就会包含与端口相关的字段。
在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过netstat -n查看);
协议号与端口号的对比:
- 协议号是存在于IP报头当中的,其长度是8位。
- 协议号指明了数据报所携带的数据是使用的何种协议,以便让目的主机的IP层知道应该将该数据交付给传输层的哪个协议进行处理。
- 端口号是存在于UDP和TCP报头当中的,其长度是16位。端口号的作用是唯一标识一台主机上的某个进程。
- 协议号是作用于传输层和网络层之间的,而端口号是作用于应用层于传输层之间的。
端口号的范围划分
端口号的长度是16位,因此端口号的范围是0 ~ 65535:
- 0 ~ 1023:知名端口号。比如HTTP,HTTPS,FTP,SSH等这些广为使用的应用层协议,它们的端口号都是固定的,所以用户一般不要使用这个范围内的端口号。
- 1024 ~ 65535:操作系统动态分配的端口号。客户端程序的端口号就是由操作系统从这个范围分配的。
认识知名端口号
有些服务是非常常用的, 为了使用方便, 人们约定一些常用的端口号,以下这些固定的端口号:
服务名称端口号ssh服务22ftp服务21telnet服务23http服务80https服务443
执行下面的命令, 可以看到知名端口号
cat /etc/services
我们自己写一个程序使用端口号时, 要避开这些知名端口号
2、两个命令
iostat
命令:该命令主要用于输出磁盘IO和CPU的统计信息。
当然你可能没有此命令,那么就需要通过软件包管理器来安装,需要注意的是,不是直接 install iostat 而是 install sysstat, iostat 也是 sysstat 的一部分,所以我们安装要安装sysstat。
其常见的选项如下:
- c:显示CPU的使用情况。
- d:显示磁盘的使用情况。
- N:显示磁盘列阵(LVM)信息。
- n:显示NFS使用情况。
- k:以KB为单位显示。
- m:以M为单位显示。
- t:报告每秒向终端读取和写入的字符数和CPU的信息。
- V:显示版本信息。
- x:显示详细信息。
- p:显示磁盘分区的情况。
例如我们要查看磁盘IO和CPU的详细信息:
CPU属性值说明:
- %user:CPU处在用户模式下的时间百分比。
- %nice:CPU处在带NICE值的用户模式下的时间百分比。
- %system:CPU处在系统模式下的时间百分比。
- %iowait:CPU等待输入输出完成时间的百分比。
- %steal:管理程序维护另一个虚拟处理器时,虚拟CPU的无意识等待时间百分比。
- %idle:CPU空闲时间百分比。
pidof
:该命令可以通过进程名,查看进程id。 pidof命令经常可以配合kill命令快速杀死一个进程。
例如,我们用pidof命令查看ssh进程。
二、UDP协议
UDP(UserDatagramProtocol)是一个简单的面向数据报的传输层协议,UDP是属于内核当中的,是操作系统本身协议栈自带的,其代码不是由上层用户编写的,UDP的所有功能都是由操作系统完成,因此网络也是操作系统的一部分。
1、UDP协议格式
主要内容:
- 16位源端口号:表示数据从哪里来。
- 16位目的端口号:表示数据要到哪里去。
- 16位UDP长度:表示整个数据报(UDP首部+UDP数据)的长度。
- 16位UDP检验和:如果UDP报文的检验和出错,就会直接将报文丢弃。
我们以前在应用层看到的端口号大部分都是16位的,其根本原因就是因为传输层协议当中的端口号就是16位的。
2、UDP的解包和分用
解包和分用对于任何一个协议来说都是它们要面临的首要任务。
UDP的解包:
从UDP的格式的首部信息中我们能够知道UDP的报头信息是固定长度的!总长度为8字节,所以我们收到一个UDP报文时,可以先读取前8个字节得到UDP报头,然后再根据报头中的相关信息,来对数据进行分用。
UDP的分用:
应用层的每一个网络进程都会绑定一个端口号。UDP就是通过报头当中的目的端口号来找到对应的应用层进程,然后对数据向上交付完成分用。
ps:
Linux
内核中用哈希的方式维护了端口号与进程ID之间的映射关系,因此传输层可以通过端口号得到对应的进程ID,进而找到对应的应用层进程。
如何理解UDP的报头?
操作系统是C语言写的,而UDP协议又是属于内核协议栈的,因此UDP协议也一定是用C语言编写的,UDP报头又是一个结构化的数据,所以UDP报头就是一个
struct
结构体!
使用C语言实现UDP的报头一般有两种方式,一种是普通结构体,一种是结构体位段。
// 普通结构体structudp_header{uint16_t src_port;// 源端口号uint16_t dst_port;// 目的端口号uint16_t udp_len;// udp的长度uint16_t udp_chk;// udp校验和};
// 结构体位段structudp_header{uint32_t src_port :16;// 源端口号uint32_t dst_por :16;// 目的端口号uint32_t udp_len :16;// udp的长度uint32_t udp_chk :16;// udp校验和};
UDP数据封装:
- 当应用层将数据交给传输层后,在传输层就会创建一个UDP报头类型的变量,然后填充报头当中的各个字段,此时就得到了一个UDP报头。
- 此时操作系统再在内核当中开辟一块空间,将UDP报头和有效载荷拷贝到一起,此时就形成了UDP报文。
3、UDP的特点
UDP传输的过程类似于寄信,其特点如下:
- 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;
- 不可靠: 没有确认应答机制, 没有超时重传机制; 如果因为网络故障该数据报无法发到对方, UDP协议层也不会给应用层,返回任何错误信息。
- 不保证有序性:报文在网络中进行路由转发时,并不是每一个报文选择的路由路径都是一样的,因此报文发送的顺序和接收的顺序可能是不同的。
- 面向数据报: UDP发送数据只能按照一个一个数据报的方式进行发送,不能够灵活的控制读写数据的次数和数量;
- 面向数据报的理解: 应用层交给UDP多长的数据, UDP加上报头以后原样发送,既不会拆分, 也不会合并。 例如用UDP传输100个字节的数据: 如果发送端调用一次
sendto
, 发送100个字节,那么接收端也必须调用对应的一次recvfrom
, 接收100个字节; 而不能循环调用10次recvfrom, 每次接收10个字节;
UDP的缓冲区
- UDP没有真正意义上的发送缓冲区,调用
sendto
会直接将数据报交给内核, 由内核将数据交给网络层,然后由网络层进行后续的传输动作。 - UDP具有接收缓冲区 ,但是这个接收缓冲区不能保证收到的UDP数据报的顺序和发送UDP报的顺序一致。 如果缓冲区满了,再到达的UDP数据报就会被丢弃。
- UDP的
socket
既能读, 也能写, 这个概念叫做全双工。
为什么UDP要有接收缓冲区?
如果UDP没有接收缓冲区,那么就要求上层及时将UDP获取到的报文读取上去,如果一个报文在UDP没有被读取,那么此时UDP从底层获取上来的报文数据就会被迫丢弃。
一个报文从一台主机传输到另一台主机,在传输过程中会消耗主机资源和网络资源。如果UDP收到一个报文后仅仅因为上次收到的报文没有被上层读取,而被迫丢弃一个可能并没有错误的报文,这就是在浪费主机资源和网络资源。
因此UDP本身是会维护一个接收缓冲区的,当有新的UDP报文到来时就会把这个报文放到接收缓冲区当中,此时上层在读数据的时就直接从这个接收缓冲区当中进行读取就行了,而如果UDP接收缓冲区当中没有数据那上层在读取时就会被阻塞。因此UDP的接收缓冲区的作用就是,将接收到的报文暂时的保存起来,供上层读取。
4、UDP使用注意事项
需要注意的是,UDP协议报头当中的UDP最大长度是16位的,因此一个UDP报文的最大长度是:
2
16
b
y
t
e
=
64
K
B
2^{16} byte = 64KB
216byte=64KB (包含UDP报头的大小)。
然而64K在当今的互联网环境下,是一个非常小的数字。如果需要传输的数据超过64K,就需要在应用层进行手动分包,多次发送,并在接收端进行手动拼装。
5、基于UDP的应用层协议
- NFS:网络文件系统。
- TFTP:简单文件传输协议。
- DHCP:动态主机配置协议。
- BOOTP:启动协议(用于无盘设备启动)。
- DNS:域名解析协议。
当然,也包括你自己写UDP程序时自定义的应用层协议。
版权归原作者 看到我请叫我滚去学习Orz 所有, 如有侵权,请联系我们删除。