【Linux】:UDP协议
朋友们、伙计们,我们又见面了,本期来给大家带来UDP协议相关的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!
C 语 言 专 栏:C语言:从入门到精通
数据结构专栏:数据结构
个 人 主 页 :stackY、
C + + 专 栏 :C++
Linux 专 栏 :Linux
目录
1. 传输层
1.1 netstat命令
1.2 端口号的划分
1.3 pidof命令
2. UDP协议
2.1 报文格式
2.1.1 如何理解报头
2.1.2 管理报文
2.1.3 理解UDP封装过程
2.1.4 UDP的缓冲区
2.2 面向数据报
2.3 使用UDP的注意事项
3. 基于UDP的应用层协议
1. 传输层
UDP属于传输层的协议,主要目的就是负责数据能够从传输端发送到接收端;
端口号标识了一个主机上进行通信的不同的应用程序;
在TCP/IP协议中,用 "源IP"、"源端口号"、"目的IP"、"目的端口号","协议号" 这样一个五元组来标识一个通信(可以通过netstat -n查看);
① 其中,源IP和源端口号可以标识互联网中唯一的一个进程;
② 服务器不担心当有多个客户端请求之后响应的数据应该发给谁,首先通过源IP就能找到是哪个客户端,再通过源端口就可以找到该客户端上的唯一的一个进程,然后将响应数据返回就可以了;
1.1 netstat命令
在Linux中我们可以使用netstat命令来查看网络连接;
选项:
- n 拒绝显示别名,能显示数字的全部转化成数字
- l 仅列出有在 Listen (监听) 的服務状态
- p 显示建立相关链接的程序名
- t (tcp)仅显示tcp相关选项
- u (udp)仅显示udp相关选项
- a (all)显示所有选项,默认不显示LISTEN相关
1.2 端口号的划分
① 0 - 1023:知名端口号,HTTP,FTP,SSH等这些广为使用的应用层协议,他们的端口号都是固定的。
② 1024 - 65535:操作系统动态分配的端口号。客户端程序的端口号,就是由操作系统从这个范围分配的。
知名的端口号:
- ssh服务器:使用22端口
- ftp服务器:使用21端口
- telnet服务器:使用23端口
- http服务器:使用80端口
- https服务器:使用443
我们自己实现的程序需要避开这些知名的端口号;
① 一个端口号只能绑定一个进程;
② 一个进程可以绑定多个端口号;
1.3 pidof命令
在查看服务器的进程id时非常方便。
语法:
pidof 进程名
功能:通过进程名查看进程id。
2. UDP协议
UDP协议的特点:
- 面向数据报:发一个完整的报文就读取一个完整的报文;
- 不可靠:没有确认机制,没有重传机制;如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息;
- 无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接。
2.1 报文格式
① 16位源端口号和16位目的端口号为了标识服务端和客户端中唯一的进程;
② 16位UDP长度表示的是整个UDP报文的总长度(自描述字段);
③ 16位UDP检验和表示在传输过程中是否出错,如果出错则直接丢弃;
④ 数据就是从应用层拷贝下来的数据。
对每一个协议都应该考虑的两个问题:
- ① 有效载荷与报头分类:
因为报头大小是固定的8字节,直接提取前8个字节大小就能拿到报头;
- ② 有效载荷向上交付
根据报头字段中的16位目的端口就能实现对有效载荷向上交付;
OS怎么知道把报文收全了呢?
因为UDP的报头大小是固定的8字节,所以如果当接收到的报文大小小于8字节,那么就可以直接丢弃了,因为连报头字段都不全;如果接收到的报文大小大于8字节,先提取8字节的报头,然后根据16位UDP长度减去报头大小就能拿到有效载荷;
2.1.1 如何理解报头
报头中的字段都是数据,所以其实报头就是一个结构体描述字段;
2.1.2 管理报文
可能存在一种情况,客户端和服务器收到了许多的UDP/TCP报文,那么他们各自并不能一瞬间将这些报文处理完毕,所以就需要对这些报文进行管理,所以就需要先描述、再组织;
所以OS就在传输层创建一个一个的struct sk_buff用来描述一个一个的报文,然后通过链表的方式将这些报文管理起来,所以OS对于报文的管理就变成了对链表的增删查改;
所以管理报文不仅要有一个描述报文的结构体,还需要有一个保存数据的缓冲区;
2.1.3 理解UDP封装过程
上面说到了OS对报文进行了先描述,再组织,对于报文有了一个描述结构体字段,那么关于UDP报文的封装过程是怎么实现的呢?
① 传输层中有一块“缓冲区”,data指针找到一块空闲空间,然后根据从应用层拷贝到的数据大小来确定tail指针的位置,比如数据的大小是5个字节,tail指针向后移动5个字节的位置,然后将数据拷贝进来;
② 因为UDP也有报头,并且报头字段是固定的,所以先对报头字段进行填充,然后计算报头的大小,计算出来是8字节,然后data指针向前移动8个字节,将报头拷贝进来,就完成了UDP报文封装的过程;
2.1.4 UDP的缓冲区
- UDP没有真正意义上的 发送缓冲区。调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作;
- UDP具有接收缓冲区。但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃;
- UDP的socket既能读,也能写,这个概念叫做 全双工;
这里所说的这个缓冲区该怎么理解呢?
因为已经有了对报文的描述结构体字段,所谓的缓冲区其实就可以将这些描述结构体连接在一个队列中,依次进行处理!
2.2 面向数据报
应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并;
假设用UDP传输100个字节的数据:
- 如果发送端调用一次sendto,发送100个字节,那么接收端也必须调用对应的一次recvfrom,接收100个字节;而不能循环调用10次recvfrom,每次接收10个字节;
2.3 使用UDP的注意事项
UDP协议首部中有一个16位的最大长度;
也就是说一个UDP能传输的数据最大长度是64K(包含UDP报头)。
3. 基于UDP的应用层协议
- NFS: 网络文件系统
- TFTP: 简单文件传输协议
- DHCP: 动态主机配置协议
- BOOTP: 启动协议(用于无盘设备启动)
- DNS: 域名解析协议