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

【Linux网络】传输层协议UDP - 详解

【Linux网络】传输层协议UDP - 详解

上三层,放在一起也可能统称为应用层,我们已经介绍过了,下面我们就来一层一层往下介绍,这篇我们就来介绍传输层最重要的两个协议之一UDP,下一篇介绍TCP

文章目录

  • 1. 传输层
    • 1.1 再谈端口号
    • 1.2 端口号范围划分
    • 1.3 认识知名端口号(Well-Know Port Number)
    • 1.4 两个疑问
  • 2. UDP协议
    • 2.1 UDP协议端格式
    • 2.2 UDP的特点
    • 2.3 UDP的缓冲区
    • 2.4 UDP使用注意事项
    • 2.5 基于UDP的应用层协议

1. 传输层

负责数据能够从发送端传输到接收端” 是传输层最核心、最根本的任务。

  • 网络层负责的是 “主机到主机” 的通信(比如,你的电脑到一台遥远的服务器)。它只关心把数据包送到目标IP地址。

  • 传输层则更进一步,负责 “进程到进程” 或 “应用到应用” 的通信。你的电脑上可能同时运行着浏览器、微信、音乐播放器等多个软件,它们都在经过网络收发数据。传输层要确保浏览器的数据交给服务器的Web服务,而不是别的。

如何实现?—— 通过端口号

1.1 再谈端口号

传输层使用 端口号来标识主机上的不同应用程序。

在这里插入图片描述
在TCP/IP协议中,用 “源IP”,“源端口号”,“目的IP”,“目的端口号”,“协议号” 这样一个五元组来标识一个通信(可以通过netstat -n查看);

在这里插入图片描述


1.2 端口号范围划分

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

1.3 认识知名端口号(Well-Know Port Number)

有些服务器是很常用的,为了使用方便,人们约定一些常用的服务器,都是用以下这些固定的端口号:

通过执行下面的命令,能够看到知名端口号

cat /etc/services

我们自己写一个程序使用端口号时,要避开这些知名端口号


1.4 两个疑问

下面两个问题其实我们在之前的文章中就已经提过,下面我们再来提一下

问题一:一个进程是否能够bind多个端口号?

答案:允许。

通过一个进程能够创建多个网络套接字,并将每个套接字绑定到不同的端口号上。这是非常常见的技术。

工作原理:

  • 一个独立的通信端点。就是每个 socket

  • 一个进程能够调用多次 socket() 系统调用,创建多个套接字描述符。

  • 然后,对每个套接字描述符调用 bind(),并指定不同的端口号。

应用场景举例:

  1. FTP 服务器:通常应用两个端口。

    • 端口 21 用于控制连接(传输命令)。

    • 另一个随机或指定的端口(如 20)用于数据连接(传输文件内容)。

  2. 自定义服务:一个后台进程可能同时提供管理接口(绑定端口 9000)和用户材料接口(绑定端口 8080)。

  3. 负载监听:一个进程允许同时监听多个端口,以处理不同类型的请求。

困难二:一个端口号是否可以被多个进程bind?

答案:通常情况下不行,但在特定条件下可以。

这是一个更麻烦的挑战,我们应该分情况讨论。

情况 A:默认情况 —— 不允许

在绝大多数情况下,操作系统不允许两个进程绑定到同一个端口号。倘若你尝试这样做,第二个进程在调用 bind() 时会失败,并得到一个类似 “Address already in use” 的错误。

原因:

  • 当数据包到达时,操作系统需要通过 IP地址 + 端口号 + 协议(TCP/UDP) 这个三元组来唯一确定应该将材料交付给哪个进程的哪个套接字。

  • 如果两个进程绑定了同一个端口,操作系统将无法做出唯一决策,导致数据混乱。

情况 B:特殊情况 —— 允许

在某些特定技术手段下,可以实现多个进程绑定同一个端口。

  1. SO_REUSEADDR / SO_REUSEPORT 套接字选项
    通过这是最常见的实现方式。通过设置套接字选项,能够允许多个套接字绑定到相同的地址和端口。

    • SO_REUSEADDR:主要用于解决“TIME_WAIT”状态下的端口快捷重用问题。在某些系统(如 Windows)和特定条件下,它也能允许多个绑定。

    • SO_REUSEPORT(Linux 3.9+ 引入):明确设计用于允许多个进程(或线程)绑定到完全相同的 IP 地址和端口号。操作系统内核会在内核层面进行负载均衡,将传入的连接均匀地分配给这些监听了同一端口的进程。

    • 应用场景:多进程网络服务器(如 Nginx)行采用 SO_REUSEPORT 来实现,让多个 worker 进程同时监听 80 端口,提高性能并避免“惊群”问题。

  2. 多播 / 组播
    一种一对多的通信模式。就是在组播中,多个进程许可加入同一个组播组,并绑定到同一个端口来接收发送到该组播地址的数据包。这

  3. 不同的传输协议
    一个端口号可以同时被一个 TCP 进程和一个 UDP 进程绑定。因为 (IP, Port, TCP) 和 (IP, Port, UDP) 被视为两个完全不同的端点。

  • 例如,一个 DNS 服务器进程可以同时在 TCP 53 端口和 UDP 53 端口上提供服务。
  1. 绑定到不同的 IP 地址
    如果一台机器有多个 IP 地址(例如,多个网卡或调整了多个虚拟 IP),那么:
  • 进程 A 允许绑定到 (IP地址1, 端口80)

  • 进程 B 可以绑定到 (IP地址2, 端口80)
    这是完全允许的,因为它们仍然是两个不同的端点。


2. UDP协议

2.1 UDP协议端格式

在这里插入图片描述
UDP首部长度:固定为8字节,包含4个16位字段。

各字段详细作用解析

  1. 16位源端口号
  • 作用:标识发送数据包的应用程序或进程。

  • 通过详解:该字段告诉接收方,数据是来自发送方设备的哪个“门牌号”(端口)。接收方在回复数据时,就能够将素材发送到这个源端口号,从而确保回复能准确送达最初发送数据的那个应用程序。此字段是可选的,假设发送方不需要接收回复,许可将其置为0。

  1. 16位目的端口号
  • 作用:标识接收数据包的目标应用程序或服务。

  • 详解:这是最关键字段之一,告诉网络设备(如路由器、交换机)和操作系统,这个数据包最终应该交给哪个正在“监听”的应用程序。例如,目的端口号是53,设备就知道这个包是发给DNS服务的;是123,则是发给NTP(时间同步)服务的。

  1. 16位UDP长度
  • 作用:指示整个UDP数据包的总长度。

  • 详解:这个长度包括了UDP首部(8字节)和数据部分。因为是16位(2字节),所以最大可以表示 2^16 - 1 = 65535字节。这意味着一个UDP数据包的最大长度是64KB。接收方通过这个字段可以知道应该从网络层接收多少数据。

  1. 16位UDP检验和
  • 否发生错误(如比特翻转)。就是作用:用于检测UDP首部和数据在传输过程中

  • 详解:

    • 发送方会根据UDP伪首部(一个包含IP地址等信息的结构)、UDP首部和数据计算出一个校验值,并填入此字段。

    • 接收方会进行同样的计算,假设计算结果与接收到的检验和不匹配,则表明数据在传输中已损坏,接收方会静默地丢弃该包,而不会要求重传。

    • 注意:这个字段在IPv4中是可选的(如果不用可置为0),但在IPv6中是强制采用的。它为UDP提供了一层最基本的可靠性保障。

  1. 数据
  • 作用:承载实际要传输的应用层信息。

  • 详解:这是UDP协议最终要运送的“货物”,比如DNS查询内容、语音通话的音频数据、视频流数据等。数据字段的长度是可变的,最大为 65535 - 8 = 65527字节(减去8字节的首部)。

所以udp报文的报头和有效载荷怎么分离呢?

具体分离步骤

  1. 定位报头的开始:
    UDP报文是从网络层(IP层)交付上来的。你拿到的是一个完整的UDP报文(即 IP 数据包中的材料部分)。这个报文的起始位置就是UDP报头的开始。

  2. 截取固定长度的报头:
    UDP报头的长度是固定不变的 8个字节(64位)。于是,你只需要:
    UDP报头 = UDP报文的前8个字节

  3. 解析报头字段以获取信息:
    通过将这8个字节的报头按图片所示的结构进行解析,能够获得关键信息:

    • 前2个字节:16位源端口号。

    • 紧接着的2个字节:16位目的端口号。

    • 再接着的2个字节:16位UDP长度。这个字段至关重要,它指明了整个UDP报文(报头+数据)的总长度。

  4. 分离有效载荷:
    L - 8字节。就是知道了总长度(假设为 L),又知道报头固定长度为 8字节,那么有效载荷的长度就
    因此,有效载荷的起始位置是第9个字节,结束位置是第 L个字节。
    有效载荷 = UDP报文的第9个字节 到 第L个字节

举例说明

  1. 假设你收到一个UDP报文,其“16位UDP长度”字段的值经解析后为 1028(单位是字节)。

  2. 分离报头:直接取前8个字节。这8个字节就具备了所有的控制信息(端口号、长度、校验和)。

  3. 计算数据长度:有效载荷长度 = 1028(总长度) - 8(报头长度) = 1020字节。

  4. 分离有效载荷:从第9个字节开始,连续取1020个字节,这部分就是发送方应用程序真正要发送的数据。


2.2 UDP的特点

UDP 核心特点详解

  1. 无连接
    就像寄信,不要求先打电话确认

  2. 不可靠
    就像寄平信,不保证对方一定能收到

  3. 面向数据报
    就像寄送包裹,每个都是独立完整的

对比 TCP 的流式传输:

TCP 像水管流水,没有明确边界

UDP 像邮寄包裹,每个包裹都是独立的


2.3 UDP的缓冲区

UDP缓冲区详解

  1. 发送缓冲区
  • 无真正的发送缓冲区:UDP协议本身并不维护一个发送缓冲区。当应用程序调用sendto发送数据时,材料会被直接封装成UDP素材报,然后交给网络层(IP层)处理。

  • 可能因网络层拥堵而阻塞:就算UDP本身没有发送缓冲区,但在数据交给网络层后,如果网络层(例如,由于出口队列已满)无法立即发送,则可能会阻塞后续的发送操作。不过,UDP不会像TCP那样进行重传或拥塞控制,它只是尽可能快地发送。

  1. 接收缓冲区
  • 存在接收缓冲区:UDP协议在内核中维护了一个接收缓冲区,用于存储接收到的UDP数据报。每个UDP socket都有自己独立的接收缓冲区。

  • 不保证顺序:由于UDP数据报是独立传输的,可能基于网络路径不同而导致到达顺序与发送顺序不一致。接收缓冲区内数据报的顺序是不确定的,应用程序必须能够处理乱序到达的材料。

  • 有限的。当缓冲区满时,新到达的UDP数据报会被丢弃,并且不会通知发送方。因此,如果应用程序不能及时读取数据,就会导致丢包。就是缓冲区大小有限:接收缓冲区的大小

  1. 全双工
  • UDP socket是全双工的:一个UDP socket可以同时进行读和写运行。这意味着同一个socket既能够接收数据也可以发送数据,而不应该像TCP那样建立连接后才能通信。

UDP资料报的丢失

由于UDP的不可靠性,数据报可能会因为以下原因丢失:

  1. 接收缓冲区满:假设应用程序读取速度跟不上接收速度,导致缓冲区满,新到的数据报被丢弃。

  2. 网络拥堵:路由器或交换机的队列满,材料报被丢弃。

  3. 校验和错误:如果UDP数据报在传输过程中发生错误,校验和不匹配,数据报会被丢弃。

应用层处理

由于UDP不提供可靠性,如果应用需要可靠性,则必须在应用层实现:

  • 序列号:用于检测丢失和乱序。

  • 确认和重传:确保数据到达。

  • 流量控制:防止发送方发送过快导致接收方无法处理。

为什么udp不需要发送缓冲区呢?

我们可以从UDP的工作方式来理解。

  1. UDP的发送过程:
  • 当应用程序调用sendto发送UDP信息报时,UDP不会对资料进行缓存,而是立即将数据封装成IP数据报并发送到网络。

  • 如果应用程序发送数据的速度超过了网络接口的处理能力,UDP不会像TCP那样将数据缓存在发送缓冲区中,而是直接丢弃信息并返回错误(或者取决于具体实现,可能不会返回错误,但不会保留数据)。

  1. UDP的无连接和不可靠特性:
  • 由于UDP不需要保证可靠性,因此它不需要维护发送缓冲区来存储已发送但未确认的数据(因为不必须重传)。

  • 同时,UDP是无连接的,因而它不需要维护连接状态,包括发送缓冲区。

  1. TCP的对比:
  • TCP是面向连接的、可靠的协议。它启用发送缓冲区来存储已发送但尚未被确认的数据,以便在超时或收到重复确认时进行重传。

  • TCP还需要实现流量控制和拥塞控制,这些都需要缓冲区来配合。

  1. UDP的方便性:
  • UDP的设计目标就是简单高效。省略发送缓冲区减少了UDP的实现复杂性和内存开销。
  1. 实际影响:
  • 由于没有发送缓冲区,应用程序调用sendto时,信息会立即被送出(或者由于某些原因被丢弃),而不会在UDP层被缓存。这意味着如果网络条件不好,数据包可能会被大量丢弃,而应用程序可能无法及时得知。

因此,UDP不需要发送缓冲区是因为其无连接和不可靠的特性所决定的。它不必须重传,也不需要流量控制,因而没有必要缓存发送的素材。


2.4 UDP使用注意事项

我们注意到,UDP协议首部中有一个16位的最大长度。也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部)。
然而64K在当今的互联网环境下,是一个非常小的数字。
如果我们需要传输的数据超过64K,就需要在应用层手动分包,多次发送,并在接收端手动拼装。

复杂的,我们并不能保证发送的多个包都会按照顺序到达,甚至可能丢包。就是但是,我们也要注意,网络环境
因此,在应用层实现分包和组装时,需要考虑以下问题:

  1. 如何分组?每个分组应该囊括哪些信息?

  2. 如何确保接收端能够正确组装?(例如,需要包含序列号、总包数、当前包序号等)

  3. 如何处理丢包和乱序?

  4. 是否应该进行重传?如何重传?

一个简单的示例,说明如何在应用层实现分包和组装:就是下面

假设我们要传输一个大型信息,我们将其分成多个包,每个包包含:

注意:由于UDP包最大为64K,我们每个包的实际素材部分需要减去我们添加的头部信息(序列号、总包数、当前包序号等)。

但是,实际上我们通常不会让UDP包接近64K,因为超过MTU(通常1500字节)会导致IP分片,而IP分片会降低传输效率和增加丢包率。

因此,我们通常会在应用层将数据分成更小的包,比如每个包1KB左右,避免IP分片。

步骤

发送端

  1. 将数据分成多个小块,每个小块加上我们自定义的协议头(序列号、总包数、当前包序号)。

  2. 依次发送这些包。

接收端

  1. 接收包,根据序列号区分不同的大数据,将同一个序列号的包收集起来。

  2. 根据当前包序号和总包数,判断是否接收完整。

  3. 如果接收完整,则按照包序号排序,然后组合成原始数据。

,这种方法可能会遇到丢包和乱序的障碍。我们可以通过以下方式改进:就是但

由于UDP本身不保证可靠性,故而我们需要在应用层搭建这些机制。这就是为什么在必须可靠传输时,我们通常应用TCP,或者运用基于UDP的可靠传输协议(如QUIC)的原因。


2.5 基于UDP的应用层协议

  • NFS:网络文件系统
  • TFTP:简单文件传输协议
  • DHCP:动态主机设置协议
  • BOOTP:启动协议(用于无盘设备启动)
  • DNS:域名解析协议

当然, 也包括你自己写UDP程序时自定义的应用层协议;

http://www.jsqmd.com/news/103712/

相关文章:

  • 2025年热门的低位码垛机/协作码垛机优质厂家推荐榜单 - 行业平台推荐
  • 22、软件更新机制全解析:从理论到实践
  • HS2-HF_Patch:让HoneySelect2游戏体验焕然一新的智能解决方案
  • 23、使用Mender进行OTA更新及设备驱动接口详解
  • Archipack建筑建模插件深度解析:从入门到精通的完整指南
  • BIThesis LaTeX模板:2025新规适配的零基础配置方法
  • EmotiVoice是否支持动态切换情感模式?实测告诉你
  • 21、嵌入式系统文件系统选择与软件更新全解析
  • EmotiVoice能否实现多人对话自动配音?流水线设计
  • 39、Linux性能分析与实时编程全解析
  • 40、嵌入式 Linux 实时性能优化与测量
  • 37、Linux系统性能分析工具指南
  • 相对名次算法的处理python
  • 38、Linux 系统中的事件跟踪工具详解
  • AI项目成立团队了
  • 34、内存管理与GDB调试全解析
  • csp信奥赛C++标准模板库STL(6):map和multimap的使用详解
  • 2025年市场调研:退火点仪ANS有哪些经销商?其介绍一下玻璃退火点测试仪ANS - 品牌推荐大师
  • 2025年比较好的高位码垛机/低位码垛机最新TOP品牌厂家排行 - 行业平台推荐
  • Javascript引擎node bun deno比较
  • Jenkins声明式流水线权威指南:从Model API基础到高级实践
  • 语音合成质量评估体系:针对EmotiVoice的测评维度
  • AgentScope深入学习-总体认识
  • 手把手教你搭建Windows系统日志监控服务器
  • KeyarchOS适配calendar-1.28-1.20140613cvs
  • 2925年12月山东枣庄洗煤设备公司专业推荐 - 2025年品牌推荐榜
  • KeyarchOS适配dar-2.5.22-1
  • 项目沟通管理 论文框架
  • 语音合成低代码平台集成:拖拽式生成EmotiVoice语音
  • C#.NET ref struct 深度解析:语义、限制与最佳实践