详解IP分片与TCP分段的区别

首先注意:一般听到的TCP分片应该称为TCP分段。IP分片与TCP分片是两个不同概念,别把IP分片与TCP分片别弄混淆了,

接下来直接划重点,两者主要区别:

1.IP分片产生的原因是网络层的MTU;TCP分段产生原因是MSS.

2.IP分片由网络层完成,也在网络层进行重组;TCP分段是在传输层完成,并在传输层进行重组. //透明性

3.对于以太网,MSS为1460字节,而MTU往往会大于MSS.

故采用TCP协议进行数据传输,是不会造成IP分片的。若数据过大,只会在传输层进行数据分段,到了IP层就不用分片。

而我们常提到的IP分片是由于UDP传输协议造成的,因为UDP传输协议并未限定传输数据报的大小。

MTU和MSS的概念

MTU

最大传输单元(Maximum Transmission Unit,MTU)是指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为单位)。
例如:以太网MTU值为1500字节,802.3的MTU值为1492字节。

MSS

最大分段长度(Maximum Segment Size)是TCP协议头部的一个选项,MSS是指TCP报文能够携带的最大数据长度,单位为字节。

MTU与IP分片

不论何种协议的链路层,都会对网络分组的长度有一个限制,因此提出了MTU的概念。如以太网的的MTU值为1500字节,若IP层(网络层)的报文长度大于MTU值时,IP报文就会被分片成小于或等于MTU值的报文。IP头部也对IP报文分片做了支持,如下图:

这里写图片描述

这里写图片描述
其中16位的标识、3位标志位( 0、DF、MF)中的DF(Don’t Fragment)和MF(More Fragment) 以及13位的片偏移用来IP报文的分片和重组。

IP分片实例:

上面提到,以太网的的MTU值一般为1500字节,假设IPv4头部20字节,UDP头部是8字节,故最大1472的应用程序数据可以避免分片。

我们用iperf发送长度为1474的把UDP数据包(包含udp头长度为1452),并用tcpdump抓包:

服务端:iperf -s -u
客户端:iperf -c 11.0.0.4 -t 100 -l 1474 -u

服务端:tcpdump -i eth0 -vv

结果如下:
这里写图片描述

由上图可知,每个分片都包含id、offset 和 flags 信息,接收方依据这几个值,把id相同的分片按照offset值(偏移量)进行重组。

其中offset 0表示第一个分片报文(length 1500 = 20字节ip头 + 1480)
其中offset 1480表示第二个分片报文(length 22 = 20字节ip头 + 2)

另外,分片报文flags [+] 表示More fragment=1,flags[none]则表示是最后一个分片报文,因此接收方可以开始重组。

MSS与TCP分片

对于TCP来说,它是尽量避免分片的,为什么?因为如果在IP层进行分片了话,如果其中的某片的数据丢失了,对于保证可靠性的TCP协议来说,会增大重传数据包的机率,而且只能重传整个TCP分组(进行IP分片前的数据包),因为TCP层是不知道IP层进行分片的细节的,也不关心。

当TCP层进行TCP分组的重传后,还会直接影响到应用层程序的性能,特别是在应用程序使用阻塞IO进行读写的时候。要理解这点,首先我们要知道当应用层程序往TCPIP协议栈写数据的时候都做了些什么事。

在应用层程序中,我们可以有自己的发送缓冲区,而TCP层本身也有自己的一个发送缓冲区,默认情况下一般是8k大小,可以通过SO_SNDBUF设置或读取。 当我们在应用层往TCP层写数据的时候,实际上是将应用层发送缓冲区的数据拷贝到TCP层的发送缓冲区中。当TCP层的发送缓冲区满或者网络空闲时,TCP层就会将其缓冲区中的数据通过IP层传到链路层的发送队列中。如果TCP层的发送缓冲区满而且应用层的数据没有写完时,内核会将write系统调用挂起,并不返回给应用层程序,直到应用层的数据全部拷贝到TCP层的缓冲区中。而由于TCP层要保证数据包的可靠性,即数据包丢失时要进行重传,那么TCP层在往网络发送TCP分组后,需要在其发送缓冲区中暂时保存发出的TCP分组数据用于后续可能的重传。

这里写图片描述

在这样的前提下,如果IP对来自TCP层的数据进行了分片, 那么就有可能使得应用层程序一直在write系统调用处挂起等待,引起性能的下降。

TCP层如何避免IP层的分片?

TCP可以避免发送方分片,它主动把数据分成小段再交给网络层。最大的分段大小(MSS)相当于MTU刨去IP头和TCP头之后的代销,所以一个MSS恰好装进MTU中。

             ______________MTU_______________           
             |                              |
---------------------------------------------
| MAC头14字节 | IP头20字节 | TCP头20字节 | 数据 |
---------------------------------------------
                                      |      |
                                      ---MSS--

注:有时TCP头不只20字节,可能包含一些TCP options,使MSS值减小,以真实情况为准。

首先,我们先回顾下TCP建立连接的3次握手:
这里写图片描述

在这3次握手中,除了确认SYN外,通信的两端还进行协商了一个值,MSS,这个值用来告诉对方,能够发送的TCP分节的大小。这个值一般是取其链路层的MTU大小减去TCP头部大小和IP头部的大小。MSS=MTU-TCP头部大小-IP头部大小. MTU的值可以通过询问链路层得知。

例如,客户端声明MSS=8960,服务器端声明了MSS=1460。三次握手之后,客户端的MTU值比服务器端大,如果发送一个9000字节的包过去可能被分片或丢弃。因此客户端会把自己的MSS也降到1460字节。

当两端确认好MSS后进行通信,当TCP层往IP层传输数据时,如果TCP层缓冲区的大小大于MSS,那么TCP层都会将其发送缓冲区中的数据切分 成MSS大小的分组进行传输,由于MSS是通过MTU减去TCP头部大小和IP头部的大小计算得出的,MSS肯定比MTU小,那么到IP层的时候就可以避 免IP层的分片。

UDP没有MSS的概念,其数据包全部交给网络层,所以可能被分片。

由于UDP是不需要保证可靠性的,那么它就不会保存发送的数据包,TCP 之所以保存发送的数据包是因为要进行重传。所以UDP本身是没有像TCP一样的发送缓冲区的。这就导致了对UDP进行write系统调用的时候,实际上应用层的数据是直接传输到IP层,由于IP层本身也不会有缓冲区,数据就会直接写到链路层的输出队列中。

在这种情况下,如果UDP数据报的大小大于链路层的MTU,那么IP层就会直接进行分片,然后在发送到链路层的输出队列中,反之,则不会进行分片,直接加上IP头部发送到链路层的输出队列中。分片和重组都会影响性能。

猜你喜欢

转载自blog.csdn.net/qq_15437629/article/details/79873993