浅析UDP包的网络传输

先讲一下MTU(Maximum Transmission Unit,最大传输单元)的概念,MTU一般为1500字节,这个包含的是什么?

以一个Ehternet II帧为例,帧头为14个字节(目的MAC地址:6个字节,源MAC地址:6个字节的,类型:2个字节),然而这14个字节是不包含在MTU里面的。在这后面的剩下的数据长度就是受MTU限制的,长度不能超过MTU,超过就要被分包了。

这后面紧跟着的就是IP Header,长度为20个字节,这个Header里面的会指明该IP包的长度,当然这个长度是包括20个字节包头在内的。这个Header里面的还会指明下面紧跟着的是什么协议的包,比如TCP是0x06,UDP是0x11。

再往下,如果是TCP当然就是跟20个字节的TCP Header,UDP的话会跟8个字节的UDP Header。

爱思考的同学这个时候可能会提出一个问题:既然每帧数据的长度受MTU限制,那我发送一个大的UDP包(比如2K长度的)岂不是要被分成多个包才能发送完?答案是一定的。

另一个问题:在收数据的时候,怎么知道把哪几个分开的包可以合成这个大的UDP包呢?答案就在IP头里面,有个Flags字段指明了这个包是不是分片的,如果是分片的,后面还有没有了分片了。注意,这个字段很重要,不分片的就是一个小包,分片的包也会知道当前的分片是不是最后一个分片。IP头里面有个Fragment offset字段也会指明当前这个分片在整个UDP包中的偏移,这就便于合并,解决了乱序的问题。

当然UDP的8个字节的头里面也指明了该UDP包的总长度,这个长度是包括8个字节包头在内的。在使用socket API时,sendto/recvfrom函数传输数据的长度是不能超过64K的。因为两个字节的无符号数最大就是65535。

而TCP的包头中就没有包长度的字段,在IP层处理分包,所以长度是没有限制的,就像水流一样。

而UDP包就是这种一整块的,如果其中一个分片丢失,整个就要丢弃。所以传输的时候,不宜发送一个很大的UDP包,避免增加丢包的概率。

与MTU相对的是,有个最小发送包长度的限制:46个字节。即使传输的数据达不到这么多,也要发送这么多数据出去。当然包头会指明要发送的实际数据长度,不够46个字节,后面会填充。

这篇文章讲的很清楚:https://blog.csdn.net/caoshangpa/article/details/51530685

最后扯另一个问题,也是我写这篇文章的原因。当使用UDP传输一个大的SIP包时,必须在IP层分片,因为SIP协议是没有分片机制的。这不像基于UDP传输RTP包,可以根据mark bit来组包,这就是RTP设计的精妙之处,它发送一个个的小包,避免在IP层分片,而通过RTP头部的sequence num识别包的乱序和丢失的情况。

上一篇:基于最大UDP数据报长度和MTU值的思考


下一篇:华为MTU值影响建立OSPF邻接关系详解