javaEE 初阶 — UDP 与 TCP 协议报文结构

1.UDP 协议报文结构




16位UDP长度,表示整个数据报(UDP首部+UDP数据)的最大长度,如果校验和出错,就会直接丢弃。

上述的这张图是任何一个计算机网络教科书上都会有的,而且都是这么画的。
但是实际上这么画的不够严谨。(为了排版方便,变形了)

更严谨的是下面的这张图。



在通过 UDP socket (也就是 send 方法拿来的数据)的基础上,在前面拼装上几个字节的报头。
(这里的拼接相当于字符串拼接,只不过此处的是二进制的,不是文本的)

UDP 报头里包含了一些携带了重要信息的特定属性,不同的协议,功能不同,报头中带有的属性信息就不同。
对于 UDP 来说,报头一共就是 8 个字节,分成 4 个部分(每个部分 2 个字节)

1.1 一个 UDP 数据报能传输的最大数据


UDP 报文长度也是 2 个字节表示的,2 个字节表示的范围是 0 ~ 655635,换算单位是64KB
也就是说,一个 UDP 数据报最大只能传输 64KB 的数据。

这个 64KB 的大小当然是非常小的,因为随便拍一张照片都是好几个 MB 的大小。

这个时候如果应用层数据报超过了 64KB 怎么办?

这里涉及到两种解决的办法。

1、需要在应用层里,通过代码的方式针对应用层数据报进行手动的分包,拆分成多个包,通过多个 UDP 数据报进行传输。
(也就是说,本来只需要 send 一次,现在需要 send 多次了)

这就好比,搬家的时候由于家具比较多,一辆车装不下,就会多叫几辆。
但是这里会多出更多的像约车,装车,卸货等一些过程,所以会比较麻烦。


2、不使用 UDP 改为 TCP (TCP 没有这样的限制)

就好比搬家的时候,一次叫一辆大点的货车,一次运输完成。

哪种方案更好?

如果使用的是第一种方案,就需要写很多的代码,还需要进行很多的测试和处理很多的 bug。
这个时候,工作量就变多了,工作时间就变成长了,幸福程度也就变低了。

所以更推荐第二种使用 TCP 的方案。

1.2 校验和


校验和的作用是验证传输的数据是否是正确的

在网络传输的过程中可能会受到一些干扰,在这些干扰下就可能会出现 “比特翻转” 的情况。

也就是 二进制位的 1 变为 0,0 变为了 1。

网络传输的本质上就是光信号/电信号,这些可能会受到一些物理环境的影响,比如电场、磁场、高能射线。

如果一个数据是 1111 0000,出现了 “比特翻转” 后就会变成 0000 1111。而一旦数据改变了,对于数据的含义可能就是致命的。

如果某个程序中经常使用 1 表示某个功能开启,0 表示关闭,本来网络数据报是想开启功能,结果翻转后,导致变成了关闭了。

这样的现象是客观存在的,是不可避免的,能做的就是及时识别出当前的数据是否有问题。

因此就引入了校验和来进行鉴别。

校验和会针对数据的内容进行一系列的数学运算,得到一个比较短的结果(比如 2 字节)

如果数据的内容一定,得到的校验和结果就一定;如果数据改变了,得到的校验和也就变了。

举一个例子,想有一个发送方和一个接收方,发送方要向接收方发送一条 hello 的数据。



接收方得到数据后需要重新计算一遍校验和,看看得到的结果和发送方发来的结果是不是一样的。
如果一样,说明数据传输没问题,如果不一样,说明数据已经出错。

如果数据内容一定,按照同样的算法得到的校验和也是 0xaabb。

如果数据出错了,接收方得到的数据是我草,那么此时重新计算校验和就会与得到的校验和不一样。
接收方得到的校验和是 0xaabb,重新计算校验和得到的可能是 0xbbaa,此时说明数据传输就出错了。


值得注意的地方

如果内容相同,得到的校验和一定相同;校验和相同,原始内容不一定相同。(存在小概率时间)
但是在实际的工程实践中,这种情况忽略不记了,一般认为,校验和相同,原始内容也想同

因为毕竟 计算得到的校验和和之前得到的校验和一样 的情况出现的概率极低,也就忽略不记了。

比方说发送 hello 的校验和是 0xaabb,而发送 我草 的校验和也是 0xaabb。(好像不太可能会出现这种情况)


校验和一般会和内容挂钩,基于数据内容算出来的校验和,只要内容一变,就能够及时发现。

比如张三去买菜,一共要买 鸡蛋、西红柿、黄瓜、小葱这四种。

一共四样,这实际上也是一个校验和,可以随时根据这四个字来验证当前买菜的状态,但这不是一个基于内容的校验和。
如果张三买的时候有一样买错了,虽然内容不一样了,但是一共还是四样,是无法及时发现的。

1.3 生成校验和的算法


针对网络传输的数据来说,生成校验和的算法有很多种,下面介绍几个比较知名的:

1、CRC:循环冗余校验

比较简单粗暴,把数据上的每个字节循环往上累加。如果累加溢出了,高位就不要了。
这种算法虽然比较好算,但是校验结果不是特别理想。

万一数据同时变动了两个比特位。(前一个字节少1,后一个字节多1这种),就会出现内容变了, 但是 CRC 没变这样的情况。


2、MD5 不是简单相加,有一系列的公式来进行更复杂的数学运算。

MD5 算法特点:

1、定长。无论原始数据多长,得到 MD5 长度都是固定长度(有4字节版本,也有8字节版本)
2、冲突概率很小。原始数据哪怕只变动一个地方,算出来 MD5 值都会差别很大。(让 MD5 结果更分散了)
3、不可逆。通过原始数据计算 MD5 很容易,通过 MD5 还原原始数据(找到哪个数据生成了这个 MD5的)很难。


3、SHA1 和 MD5 的思路是非常相似的。

2. TCP 协议报文结构


TCP 协议的特点是:有连接、可靠传输、面向字节流、全双工



上述的图片就是 TCP 的报头,16 位源端口号16 位目标端口号 和 UDP 是一样的,都是表示端口号。

16 位校验和 也是和 UDP 是一样的。

32 位序号(序列号)、32 位确认序号(确认应答号)、16 位窗口大小、16 位紧急指针 后面再做详细的介绍。

2.1 首部长度


一个 TCP 报头长度是可变,不是像 UDP 一样是固定的 8 个字节。
因此,首部长度 就描述了 TCP 报头具体多长,另外,选项之前的部分是固定长度(20字节)。
首部长度减去 20 字节得到的就是选项部分的长度,需要注意的是,此处的首部长度是 4 bit 位

4 bit 表示的范围是 0 ~ 15,首部长度的单位不是字节,而是 4 个字节。
如果首部长度值是 5 ,表示整个 TCP 报头是 20 字节。(相当于没有选项)
如果首部长度值是 15 ,表示整个 TCP 报头是 60 字节。(选项相当于 40 个字节)

2.2 保留位


保留 相当于是 C语言中的保留字,虽然现在还没用,但是保不准以后要用。所以会在这先占个位置,别人无法使用。

进行程序开发的时候,其中一个重点考虑的事情就是可扩展性。有些功能可能暂时不需要,但是保不准将来需要。
此处的 TCP 保留 6位,也是为了以后的扩展考虑的。

保留位的作用:

对于网路协议来说,扩展升级是一件成本极高的事情。
比如说 UDP 的报文长度是 2 字节,因此一个包最大 64KB,如果要把 UDP 协议升级一下,要它支持更大的长度。
比如说,把报头长度使用 4 字节表示,这在理论基础上是可行的,但是实际操作的成本极高。

如果想要升级就要把全球可以上网的设备的操作系统同时升级成支持 4 字节的UDP,这是非常困难的。
如果引入了 “保留位”,此时升级操作的成本就会低不少。

如果后序 TCP 引入了一些新的功能,就可以使用这些保留位字段。
此时对于 TCP 本来的报头结构的影响是比较小的,老的设备即使不升级也更容易兼容。

2.3 选项与 6 位标志位


此处的选项相当于对这个 TCP 报文的一些属性进行解释说明的。

  • URG:紧急指针是否有效
  • ACK:确认号是否有效
  • PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
  • RST:对方要求重新建立连接;我们把携带RST标识的称为 复位报文段
  • SYN:请求建立连接;我们把携带SYN标识的称为 同步报文段
  • FIN:通知对方,本端要关闭了,我们称携带FIN标识的为 结束报文段
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

与大师约会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值