当前位置: 首页 > news >正文

【Linux网络编程】传输层协议 - UDP

目录

传输层

UDP协议

UDP协议端格式

UDP的特点

面向数据报

UDP的缓冲区

UDP的注意事项

基于UDP的应用层协议


传输层

传输层是负责将数据从发送端转发到接收端的。传输层及以下都是属于操作系统的。

再谈端口号

端口号标识了一个主机上进行通信的不同的应用程序。当协议栈接收到报文之后,一定要能够将报文发给上一层,从传输层交给应用层时,传输层报头中就会有对应服务的端口号,根据端口号即可将报文交给指定的服务。

上图理解为HTTP服务是多进程的。客户端发送请求后,服务器接收到请求后,是需要发送应答的,发送应答就一定需要知道客户端的IP地址和端口号,这是服务器通过recvfrom得到的。所以,通过服务器的IP地址和端口号、客户端的IP地址和端口号,即可标识一对通信。

实际上,在应用层获取到的IP地址是记录在IP报文的首部的,端口号是记录在TCP/UDP报文的首部的。并且在报文当中,是会含有传输层所采用的协议的字段的。所以现在可以使用一个五元组标识一对通信,源IP地址、目标IP地址、源端口号、目标端口号、传输层所采用的协议

端口号范围划分

  • 0 - 1023:知名端口号。HTTP、FTP、SSH等这些广为使用的应用层协议,他们的端口号都是固定的
  • 1024 - 65535:操作系统动态分配的端口号。客户端程序的端口号,就是由操作系统从这个范围分配的

Linux中,有一个配置文件记录了网络服务中常见的端口号:/etc/services

1. 一个进程是否可以绑定多个端口号?

可以,甚至可以既绑定TCP的端口号,又绑定UDP的端口号。

2. 一个端口号是否可以被多个进程绑定?

不能。因为需要根据端口号区分进程。

UDP协议

UDP是不考虑连接的,只要套接字创建好了,就可以直接发送消息。因为UDP面向数据报的,所以是不需要考虑粘包问题和字节流问题的,UDP的报文长度在内核中OS是知道的。

UDP协议端格式

struct udphdr {__be16  source;     // 源端口号(16位,大端字节序)__be16  dest;       // 目标端口号(16位,大端字节序)__be16  len;        // UDP数据报长度(头部+数据,单位:字节)__be16  check;      // 校验和(覆盖头部和数据,可选)
};

传输层及以下,都是属于OS的,所以在这里面的协议都是结构体。在OS中,与应用层是不同的。在OS中可以直接传输结构化数据,是二进制传输的,不需要进行序列与反序列化。因为对于OS而言,效率更重要。添加报头的本质就是定义一个结构体对象,然后将这个结构体对象与上层的报文的拷贝合并起来。

上面的图片就是一个UDP报文,前8个字节就是UDP报头,后面的数据就是有效载荷。

我们来看几个问题:

1. UDP是如何解包的?

因为UDP的报头是固定长度的,8字节。直接读取UDP报文的前8个字节,将剩下的有效载荷交给上层即可。

2. UDP是如何做到分用的?

UDP的报头中有一个目的端口号。而UDP服务器绑定过端口号,就会使用报头中的端口号进行匹配。就能够找到对应进程了,再将有效载荷交给这个进程即可。之前说端口号最大是65536,因为一个端口号只有16位。这是由协议决定的。

3. UDP是面向数据报的,如果有多个UDP报文粘在在一起了,怎么确保准确读完有效载荷呢?

报头中还有16位的UDP长度。这表示的是整个UDP报文的长度,单位是字节,减去8即可得到有效载荷的长度。

虽然UDP不保证可靠性,即报文丢了就丢了。但是UDP会保证交给上层的数据是合法、可靠的。所以会有一个16位的UDP校验和。用来对整个UDP报文做校验,校验失败了直接丢弃,校验成功了才向上层交付。

报头中有有效载荷的长度,这在我们之前自己实现的网络版计算器和HTTP协议中都有使用。像这种在报头中会描述自己有效载荷的字段,称为协议中的自描述字段

4. UDP是如何进行封装的?

当我们调用sendto将应用层的报文发送到传输层时。UDP中为了能够对应用层发送过来的报文进行封装,就需要有一段缓冲区。当应用层发送报文时,实际上就是将报文拷贝到了缓冲区里面。而在OS中,发送报文的同时可能也在接收报文,所以oS就需要对这些报文进行管理。每一个报文就是一个sk_buff,sk_buf是一个报文的管理结构,里面会包含很多字段,其中就有指向应用层发送过来的报文的指针。当应用层刚将报文发送给传输层时,会将这个报文拷贝到传输层对应的缓冲区中台,一个指针end指向拷贝过来的报文的结束。

到达传输层的报文是需要添加UDP报头的,也就是进行封装,怎么添加UDP报头呢?

  1. head -= sizeof(struct udphdr)
  2. 填写UDP报头
    (struct udphdr*)head -> source = 8080;
    (struct udphdr*)head -> dest = 9090;
    ...

这就是UDP封装。要将添加了UDP报头的数据发送给下一层要怎么发送呢?
只需要将sk_buff链入到网络层的相应管理结构中,这样带着数据就下去了。并不会将传输层缓冲区内的报文拷贝到网络层缓冲区当中,因为只要通过指针即可访问。

UDP的特点

无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接;

不可靠:没有确认机制,没有重传机制;如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息;

面向数据报:不能够灵活的控制读写数据的次数和数量。

这里的可靠与不可靠不是优缺点,而是特性。因为有的情况下对可靠性的要求并不那么高。TCP是可靠的,为了保证可靠性,它就要做更多的工作。不可靠说明这个协议本身比较简单一些。

面向数据报

应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并。发送一次,接收方的应用层读取UDP报文时,一次就必须读完一整个UDP报文。TCP则是发一次,可能需要接收多次才能接收完。如果发送端调用一次 sendto,发送100 个字节,那么接收端也必须调用对应的一次recvfrom,接收100个字节;而不能循环调用10次recvfrom,每次接收10个字节。

UDP的缓冲区

我们之前说过,TCP的一个套接字就对应一个发送缓冲区和一个接收缓冲区。所以TCP是全双工的。TCP要保证接收到的报文与发送时的顺序一致,也属于可靠性的一种。

UDP是有接收缓冲区的,因为收到数据时,可能并不在recvfrom中。UDP并没有真正意义上的发送缓冲区,因为它不需要。因为UDP是不可靠的,应用层将报文交给UDP后,UDP直接添加报头然后发给下一层。但是,不存在发送缓冲区并不影响它的全双工。

UDP的注意事项

我们注意到,UDP协议首部中有一个16 位的最大长度。也就是说一个UDP能传输的数据最大长度是 64K(包含 UDP 首部)。如果我们需要传输的数据超过64K,就需要在应用层手动的分包,多次发送,并在接收端手动拼装。既然已经拆分了,不如使用TCP了。

基于UDP的应用层协议

  • NFS:网络文件系统
  • TFTP:简单文件传输协议
  • DHCP:动态主机配置协议
  • BOOTP:启动协议(用于无盘设备启动)
  • DNS:域名解析协议
http://www.dtcms.com/a/296303.html

相关文章:

  • 【数据结构初阶】--二叉树(二)
  • M²IV:面向大型视觉-语言模型中高效且细粒度的多模态上下文学习
  • BI 系统数据看板全解析:让数据可视化驱动业务决策
  • ESP32使用 vscode IDF 创建项目到烧录运行全过程
  • C++学习笔记(八:函数与变量)
  • 云原生架构下的服务器运维挑战与解决方案
  • 【CVPR 2025】即插即用,MobileMamba三阶段架构+Wavelet增强,颠覆轻量模型格局!
  • Qt Quick 3D渲染
  • 云端哨兵的智慧觉醒:Deepoc具身智能如何重塑工业无人机的“火眼金睛”
  • 5种最佳方法将iPhone语音备忘录传输到Mac
  • 清除浮动以及原理
  • 移动管家手机控车便捷性如何
  • 秋招Day18 - MyBatis - 基础
  • tensorflow安装(CPU版本)
  • 爬虫算法原理解析
  • Python爬虫实战:研究picloud相关技术
  • WebRTC指纹——深度分析(中篇)
  • qlib的Alpha158类定义
  • RHCE(4)
  • CDH yarn 重启后RM两个备
  • 2025.7.24 01背包与动态规划复习总结
  • 【前端】jQuery加载JSON文件并赋值方法
  • 字节的机器人模型 GR-3
  • Hyperledger Caliper 一键测试环境部署脚本
  • LeetCode|Day24|383. 赎金信|Python刷题笔记
  • Android安全存储:加密文件与SharedPreferences最佳实践
  • C++右值引用与移动语义详解
  • 低速信号设计之 JTAG 篇
  • lesson23:Python面向对象高级特性详解
  • 2025年6月GESP(C++六级):学习小组