首页 > 其他分享 >UDP协议精华总结

UDP协议精华总结

时间:2023-03-25 11:55:56浏览次数:45  
标签:总结 UDP 字节 IP 精华 分片 长度 数据

引入

本文面向有一定计网基础的读者。

TCP, UDP, IP 可以说是计网的常客了,它们三紧密联系,以至于经常看见“TCP/IP”这样的名词,但实际上 UDP 也是基于 IP 的,但似乎很少见“UDP/IP”。

也不奇怪,人人都说 UDP 与 TCP 相比过于简单,因此提的少。但是这并不意味着 UDP 用的少,相反它经常用于那些不要求数据可靠性的场景:音频传输、视频传输、在线游戏等。这些场景对数据可靠性、完整性要求不高,丢失少量数据包带来的影响并不大,比如音频传输中丢包的经典表现是听不清或听不到对方说的话;视频传输中丢包的经典表现是卡顿。

我认为先熟悉简单的 UDP 协议,能更好地理解复杂的 TCP 协议。

UDP协议简介

UDP, User Datagram Protocol 用户数据报协议。UDP 是传输层协议之一,应用程序可以调用该协议向其他计算机发送数据,只不过它不像它的兄弟 TCP 一样可靠,UDP 只是简单的将数据发送给指定目标,不提供任何保证(差错纠正、流量控制、拥塞控制,这些都是 TCP 才有的)。

与 TCP 相比,UDP 仅有的两个优点是:

  1. 保留消息边界:一般情况下,应用程序调用 UDP 发送数据时,只产生一个 UDP 数据报,从而也只发送一个 IP 数据报。从 socket 编程的角度来说就是,发送端调用 API 发送一次数据,接收端也只需要调用一次 API 便可接收到完整的数据。
    • 其实这里面有很多前提的,比如:(1)UDP 协议实现会限制一次发送 UDP 数据报的长度,尽量避免发生 IP 分片;(2)数据在传输过程中没有丢失、出错,接收端接收到的是完整无误的 UDP 数据报。
  2. 提供差错检测:虽然 UDP 不提供差错恢复,但是它却提供了差错检测(是的,做事只做一半,能检测到差错,却不能恢复)。

一句话总结:UDP 是无连接、面向消息、保留消息边界、具有差错检验功能的传输层协议。

UDP头部

一个典型 UDP 数据报的格式如下图所示:

image-20230323171445425

各个字段的解释如下:

  1. 源端口:占 2 字节,用于标识发送方进程(端口是抽象概念,没有物理实体)。可选字段,如果不要求对方回复,可以置 0。

  2. 目的端口:占 2 字节,用于标识接收方进程。

  3. 长度:占 2 字节,表示整个 UDP 数据报的长度,单位是字节。由于 16 比特能够表示的无符号数范围是 \([0, 2^{16} - 1] = [0, 65535]\),因此理论上 UDP 数据报最大长度为 65535 字节,即 64KB。

    • 实际上该字段最小值 8(没有 payload,只有 UDP 头)。
    • 该字段是冗余的,因为 IP 头里也有一个长度字段表示 IP 数据报长度,UDP 数据报的长度可以间接计算得到:[ UDP数据报长度 = IP数据报长度 - IP头部长度 ]。
  4. 检验和:占 2 字节,用于表示整个 UDP 数据报存在比特差错,通过某种算法计算得到。IPv4 可选但强烈推荐,IPv6 强制要求。

    • 一个端到端的检验和。由发送方计算,接收方检测,传输过程中不会被途经设备修改(除非经过了 NAT 地址转换)。
    • 若该字段为 0x0000 则表示发送方没有计算检验和。因此当计算结果恰好为 0x0000 时,会设置为反码 0xFFFF(那计算结果有没有可能恰好是 0xFFFF 呢?这冲突吗?我不知道= =)。
    • 两个“虚”的部分参与检验和的计算:虚 0 字节和虚 IP 头部,但这两个虚的部分不会真正发送出去,只用于计算检验和。检验和计算要求 UDP 数据报的长度为偶数,因此会在奇数长度的 UDP 数据报末尾填充字节 0。此外,它还使用了一个 12 字节的伪 IP 头部,包含源 IP 地址、目的 IP 地址、零填充、协议号、长度。
  5. 负载:应用程序要发送的数据。

image-20230324094041297

关于最大UDP数据报长度的讨论

上文介绍过,仅从 UDP 协议的角度来说,UDP 数据报的最大长度是 65535 字节。

但是 UDP 数据报是封装在 IP 数据报里的,而 IP 数据报的最大长度也是 65535 字节,也就限制了最大 UDP 数据报的最大长度要扣除一个 IP 头的长度。没有选项的 IP 头长度为 20 字节,因此一般 UDP 数据报的长度为 65515 字节,再扣除 8 字节的 UDP 头部长度,UDP 的最大负载为 65507 字节。

实现限制

不过,这一切都建立在 IP 头没有额外选项的前提下,这对于 UDP 协议的实现来说太过麻烦,毕竟实现者无法判断用户是否使用 IP 头的额外选项。

因此在实现中会提供 API 供应用程序查询最大 IP 数据报长度,典型值为 8192 或 65535 字节(当然也提供了 API 设置该值,但有没有范围限制呢?鬼知道这么实现者的心思= =)。

查询得知最大 IP 数据报长度后,便可自行决定最大 UDP 数据报长度。

UDP数据报截断

上文介绍过,UDP 是保留消息边界的传输协议,发送方调用发送 API 发送一次,接收方只需要调用一次接收 API 便可接收到完整的数据报。

然而在实现中,接收 API 允许指定一次读操作完成时返回的最大字节数,在不知道接收到的 UDP 数据报究竟多大的情况下,有可能并不能一次性全部接收完(虽然通过种种限制,一般情况下都是能一次接收完的)。当接收到的 UDP 数据报长度超过了指定的读取大小会发生什么呢?

通常做法有两个:截断和留到下个读操作。截断直接丢弃了超出的部分,导致接收方得到的数据不完整;留到下个读操作将超出部分保留,导致每次读操作都不能保证读到一个完整的数据报。因此截断是大多数实现者的做法。

路径MTU发现

MTU, Maximum Transmission Unit 最大传输单元,是链路层的最大有效载荷,即最大的 IP 数据报的大小,典型值为 1500 字节。

路径 MTU 是指:包含所有链路的整个网络上,最小的 MTU。

路径 MTU 发现是指:通过设置不发生 IP 分片,确定到达目的地的 MTU 大小。

UDP数据报与IP分片

IP 分片概念:当 IP 数据报大小超过 MTU 便要进行分片,将 IP 数据报拆分为多个片段,每个片的最终大小都不超过 MTU。

  • 若设置了 IP 头不分片标志(DF, Don't Fragment),则转发设备直接丢弃该数据报。
  • IP 分片可能发生在多个设备上进行多次,因为各个局域网链路的 MTU 可能不同。
  • IP 分片只在目的地进行重组。因为分片经过路由转发的路径有可能不同,一个转发设备大概率不能“看到”所有分片,只能看到分片的一个子集,不具备重组分片的条件。

通过一个例子来理解 IP 分片的原理:以 MTU=1500 为例,对一个大小为 3020 字节、负载为 UDP 数据报的 IP 数据报进行分片的结果如下图所示。

image-20230324103534355

原理要点概括如下:

  • IP 分片针对的是 IP 数据报的负载。

  • 每个分片都有 IP 头部。

  • MF、标识和片偏移用于目的地进行分片重组,获得原始 IP 数据报,这三个字段在 IP 头部中,图中没有详细展示)。

    • 标识:用于标识分片属于同一个原始 IP 数据报,由进行分片的设备设置,来自同一个原始 IP 数据报的分片的标识相同。

    • MF:More Fragment,表示还有更多分片。最后一片的 MF=0,其余片的 MF=1。

    • 片偏移:分片负载的第一个字节在原始 IP 数据报中的偏移量,单位是 8 字节。

分片具体过程如下:

  1. 因此分片个数的计算公式为:\(分片个数 = \lceil \frac{IP负载长度}{MTU -IP头长度} \rceil\),此例子中为 \(\lceil \frac{3000}{1500 - 20} \rceil = 3\)
  2. 显然第一个分片能承担 1480 字节负载,剩余 3000-1480=1520 字节;
  3. 第二个分片继续承担 1480 字节负载,剩余 1520-1480=40 字节;
  4. 第三个分片承担剩余 40 字节负载。

IP 分片的其他要点:

  1. 每个分片都要有 IP 头部,会引入额外的传输开销。

  2. 每个分片的 IP 头部都要修改总长度字段。

  3. 任何一个分片在转发过程中丢失,都意味着整个数据报丢失。

  4. 通常转发设备优先转发片偏移更大的分片,这样做的好处是接收方可以提前确定所需缓存空间的最大值(最后一个分片的片偏移 * 8 + 最后一个分片的总长度 = 原始 IP 数据报的长度)。

重组超时和超时重传

重组超时:接收方 IP 层收到任何一个分片就启动一个计时器,随后到达的其他分片不会重置计时器,若计时结束还没有收到所有分片,则重组超时。

响应:根据 IP 协议实现的不同而略有差异,所有方案都丢弃所有分片,部分方案产生 ICMP 错误报文通知发送方,而部分方案不产生 ICMP 错误。

超时重传:UDP 本身没有超时重传机制,需要应用程序自行设置。

UDP-Lite

UDP-Lite 是 UDP 的改进,仅仅将 UDP 头部中的长度字段改成了检验和覆盖范围

出现原因:有些应用程序可以接受在发送和接收的数据里存在比特差错,那么检验和就没有必要覆盖整个数据报,只需要覆盖那些不允许存在比特差错的数据。

UDP-Lite 头部如下所示:

image-20230324095552969

检验和覆盖范围:占 2 字节,单位为字节,表示从 UDP-Lite 头部的第 1 个字节开始,被检验和覆盖的字节数。

  • 0 是特殊值,表示覆盖整个数据报,即 64KB。
  • 1-7 无效,因为头部都占 8 字节了。

标签:总结,UDP,字节,IP,精华,分片,长度,数据
From: https://www.cnblogs.com/zwjason/p/17254449.html

相关文章

  • 600 条最强 Linux 命令总结
    1.基本命令uname-m显示机器的处理器架构uname-r显示正在使用的内核版本dmidecode-q显示硬件系统部件-(SMBIOS/DMI)hdparm-i/dev/hda罗列一个磁盘的架构特......
  • 2023、03、24学习总结
    写了第一个查询,用同样的方法写第二个线路查询出现问题,无法正常查询,明天在找问题  ......
  • 总结20230324
    今日是周五,虽然课最多,但是还是很喜欢今天的,因为明天又迎接来了双休。今天上了计算机网络、概率论、实用英语阅读与翻译、web应用开发技术、数学建模B。计算机网络今天进......
  • 3.24总结
    今天基本上光上课了,下课玩了一会,基本没学东西今晚体验的东西如下:首先对viewPager有了一点新的认知,就是可以做轮播图,初步认识了Handler以及分线程的机制。然后就是对底部......
  • 3.24周五每日总结
    今天主要学习了androidstdio中的Textview和button部件。学习了他们主要的属性。在Textview部件中主要实现的有:显示省略号操作<TextViewandroid:id="@+id/tv_2"a......
  • 今日总结之maven的使用
    在maven项目中的pom.xml文件配置依赖的jar包的坐标  例如配置mysql的jar包就可以导入mysql的坐标<dependencies><!--https://mvnrepository.com/artifa......
  • 每日总结2023-03-24
    今天进行了北京地铁线路的导入数据库,进行了代码优化更改,进行了北京地铁的查询。我的搭档完成了地图的设置。下面是演示:  代码量大概100行。......
  • 2023.3.24每日总结
    importjava.util.*;importjava.io.*;publicclassSubway{privateMap<String,Set<String>>lines;//存储地铁线路信息privateMap<String,Set<Strin......
  • 每日总结-23.3.24
    关于计算日历privateintxianshilianxu(intyear,intmonth,intday,Stringuser){intjianchishijian=0;TextViewtextView1=findViewById(......
  • 1.关于等价代换总结
    等价代换何时该用其实这还是比较纠结的问题在书中一般只阐述了乘除法,武的书添加了部分加减法,(加减和不为零),具体原因没有给出,然后做题又有指数形式,武说指数没有定义定义,......