网络原理(六): UDP 协议

目录

[1. UDP 协议](#1. UDP 协议)

[1.1 协议特点](#1.1 协议特点)

[1.2 协议报文格式](#1.2 协议报文格式)

[1.2.1 UDP 长度](#1.2.1 UDP 长度)

[1.2.2 校验和](#1.2.2 校验和)


1. UDP 协议

在进行网络编程时, 我们已经对 UDP 协议进行了简单了解. 并且应用层的很多操作, 需要调用传输层的提供的接口, 基于 socket api 来进行完成的.

1.1 协议特点

UDP 协议具有以下特点:

  1. 面向数据报
  2. 不可靠传输
  3. 全双工
  4. 无连接

在进行网络编程使用 UDP socket api 进行数据传输时, 我们就对其中的一些特点有了一些感受:

面向数据报体现于: 每发送(send)或接收(receive)一次消息, 都是一个完整的 udp 报文.

全双工体现在: 不论是客户端还是服务器, 都可以进行 send 和 receive 操作.

无连接体现在: UDP 报文直接发送, 对端就可以接收, 并没有像 TCP 那样 accept 的过程.

不可靠传输, 是指消息发出后, 就不管了(不管数据是否成功发送到对端). 这一点并没有在编程时具体体现, 接下来我们通过 udp 协议的报文格式来了解这一特点.

1.2 协议报文格式

UDP 数据报由两个部分组成:

  1. UDP 报头
  2. 载荷(完整的应用层数据包)

其中, 载荷就是完整的应用层数据报.

报头, 大小为 64 个 bit 位, 8 个字节, 由以下四个部分组成:

  1. 源端口号
  2. 目的端口号
  3. 报文长度
  4. 校验和

其中, 每个部分都占了 2 个字节.

至于源端口号和目的端口号的作用, 这里就不再赘述了, 主要聊一聊其中的 报文长度 和 检验和.

1.2.1 UDP 长度

UDP 报文格式中的长度这一部分, 表示的是整个 UDP 数据报的长度, 即报头 + 载荷的长度.

由于大小为 2 字节, 也就是 16 个 bit 位, 所以 UDP 数据包长度的范围为 0~2^16-1, 也就是 0~65535, 所以一个 UDP 数据报最大只能为 65535 个字节, 也就是 64kb.

由于报头部分的大小是固定的, 8 字节, 这相对于 64kb(65535 字节) 来说是可以忽略不计的.

所以, 当我们面试表述 UDP 报文大小的上限时, 既可以说 64kb 是整个 UDP 数据包的上限, 也可以说是 UDP 携带的载荷的上限.

64 kb, 在设计 UDP 的那个年代, 确实是一个充裕的大小, 但是放到 2024 年的今天, 就是一个非常小的数字了, 随随便便一张照片就可能是几个 MB.

所以要发送数据的大小超出 UDP 数据包可以承载的大小的情况是经常发生的, 而当发送的大小一旦超过了 64kb, UDP 数据包就会被直接截断, 对方拿到的数据就会出错, 那么如何解决这个问题呢?? 有两个方案可以选择:

  1. 方案一: 在应用层代码上进行拆包操作, 把一个大的应用层数据报拆成很多小的数据包, 再使用多个 UDP 数据包进行传输.
  2. 方案二: 使用 TCP 协议, 使用 TCP 数据包进行传输(TCP 没有长度的限制).

方案一, 是一个工作量比较大的方法, 需要对代码进行大量的修改, 写大量的逻辑来实现分包组包的工作, 并且一不小心可能就写出了隐藏 bug, 效率太低.

所以, 在工作中, 我们会优先选择简单且不易出错的方案来解决问题, 即采用方案二, 使用 TCP 来解决 UDP 数据包大小限制的问题.

可能大家心中有一个疑问: 为啥不直接修改 UDP 的报文格式, 直接把 UDP 本身改的大一点呢??

其实, 要修改 UDP 很容易, 但是难就难在, UDP 已经内置在各种的操作系统中, 一旦发生变动, 就会造成很大的影响, 比如通信双方, 一方进行了修改, 另一方没有进行修改, 那么 UDP 数据包就会传输失败, 导致不能使用 UDP 进行通信. 并且, 修改也会牵扯到系统兼容性的问题, 所以, 通信双方谁先改, 谁可能就会出现问题.

所以 UDP 可以说是积重难返了, 目前也只能这样子~~

1.2.2 校验和

UDP 报文中的校验和, 作用是为了验证传输的数据是否发生修改.

注意, 这里的校验和与 HTTPS 中数字签名的校验和不同, HTTPS 数字签名的校验和是为了反正数据被黑客篡改(防人), 但是这里 UDP 的校验和, 与安全性无关, 而是防止传输过程中出现"比特翻转".

比特翻转, 就是在传输的过程中, 由于外界的影响, 导致数据中的某些 bit 位0变1, 1变0.

(数据都是以光电信号或者电磁波的形式进行传输的, 很容易收到外界的干扰)

验证的过程如下:

  1. 发送之前, 会把整个数据报中的数据代入, 计算得出一个校验和, 并将数据和校验和一同发给对端.
  2. 对端收到数据后, 根据收到的数据, 再次计算校验和, 将两个校验和进行对比, 如果校验和不一致, 说明有数据发生了比特翻转, 直接丢弃.

这里 UDP 采用的 CRC(循环冗余校验) 的方式来计算校验和:

  • CRC: 把 UDP 报文中的每个字节(除了校验和位置外), 都当做整数, 进行累加, 即使溢出也没关系, 继续加, 最终得到的数据就是 CRC 校验和.

所以, 如果在传输过程中, 有 bit 位发生了翻转, 那么两次计算得到的校验和也会不同.

我们可以认为, 如果两个数据是相同的数据, 那么计算得到的校验和一定是相同的.

但是, 当两次计算的校验和相同时, 两个数据不一定是相同的.

因为, 这其中可能存在变数, 例如: CRC 是累加的方式计算的校验和, 如果第一个字节发生的翻转, 使得值变小了, 而第二个字节发生的偏转又使值变大了, 而恰恰这两次偏转各自的差值又相互抵消, 那得到的校验和依然是相同的.

虽然, 可能出现上述情况, 但是这种情况发生的概率是非常小的(发生翻转的概率本来就小, 再加上两次偏转的影响又相互抵消, 概率就小之又小了), 所以在实际开发中, 我们可以忽略这种情况的存在.

综上, 我们可以通过 UDP 报文中的校验和这一部分, 来确定数据在传输时, 是否发生了修改~


++END++

相关推荐
七七&5563 小时前
2024年08月13日 Go生态洞察:Go 1.23 发布与全面深度解读
开发语言·网络·golang
元清加油3 小时前
【Golang】:函数和包
服务器·开发语言·网络·后端·网络协议·golang
向日葵.5 小时前
fastdds.ignore_local_endpoints 属性
服务器·网络·php
athink_cn7 小时前
HTTP/2新型漏洞“MadeYouReset“曝光:可发动大规模DoS攻击
网络·网络协议·安全·http·网络安全
zzc9217 小时前
TLSv1.2协议与TCP/UDP协议传输数据内容差异
网络·测试工具·安全·wireshark·ssl·密钥·tlsv1.2
Peter_Deng.8 小时前
Linux 下基于 TCP 的 C 语言客户端/服务器通信详解(三个示例逐步进阶)
服务器·c语言·网络
wxy3199 小时前
嵌入式LINUX——————TCP并发服务器
java·linux·网络
蒋星熠9 小时前
C++零拷贝网络编程实战:从理论到生产环境的性能优化之路
网络·c++·人工智能·深度学习·性能优化·系统架构
huluang9 小时前
医院网络安全重保行动方案
网络·安全
九州ip动态9 小时前
如何安全使用改IP软件更改异地IP地址?
网络·tcp/ip·安全