TCP/UDP/IP分片

 

我们知道,当应用层程序之间进行网络数据传输时,在发送端,数据会从应用层沿着协议栈向下传输,通过TCP/IP层,然后经由链路层发送出去,而在接收

端,则是相反的顺序,数据经由链路层接收,然后沿着协议栈向上传输,通过IP/TCP层,最后由应用层程序进行读取。

 

 

而在IP层往链路层传输数据的时候,往往会做一个分片的操作,对于大多数链路层来讲,它都有一个最大传输单元(MTU),表示能够发送数据量的大小,它

是由硬件决定的。比如以太网的MTU为1500字节。当IP层传输给链路层的数据量大于其MTU时,那么IP层就会将数据拆分为小于其链路层MTU的数据片,再传

输给链路层进行发送。

 


但是对于不同的传输层协议(TCP/UDP)来说,在IP层上,需不需要进行分片是不同的。

 

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建立连接的3次握手:

 

在这3次握手中,除了确认SYN分节外,通信的两端还进行协商了一个值,MSS,这个值用来告诉对方,能够发送的TCP分节的大小。这个值一般是取其链路

层的MTU大小减去TCP头部大小和IP头部的大小。MSS=MTU-TCP头部大小-IP头部大小. MTU的值可以通过询问链路层得知。

 

当两端确认好MSS后进行通信,当TCP层往IP层传输数据时,如果TCP层缓冲区的大小大于MSS,那么TCP层都会将其发送缓冲区中的数据切分成MSS大小

的分组进行传输,由于MSS是通过MTU减去TCP头部大小和IP头部的大小计算得出的,MSS肯定比MTU小,那么到IP层的时候就可以避免IP层的分片。

 

 

 

UDP层的分片

如果我们采用的是UDP协议而不是TCP协议呢?在IP层会不会进行分片?由于UDP是不需要保证可靠性的,那么它就不会保存发送的数据包,TCP之所以保存

发送的数据包是因为要进行重传。所以UDP本身是没有像TCP一样的发送缓冲区的。这就导致了对UDP进行write系统调用的时候,实际上应用层的数据是直接

传输到IP层,由于IP层本身也不会有缓冲区,数据就会直接写到链路层的输出队列中。

 

在这种情况下,IP层会不会对来自UDP的数据进行分片呢?这个取决于UDP数据报的大小。如果UDP数据报的大小大于链路层的MTU,那么IP层就会直接进

行分片,然后在发送到链路层的输出队列中,反之,则不会进行分片,直接加上IP头部发送到链路层的输出队列中。

 

 

TCP/UDP实验

看完了理论,让我们实践一把,看是否与以上的理论相符。

 

对于TCP来说,它是尽量避免分片的。假设我们这里要发送给TCP层的数据大小为2748个字节,这个大小是明显大于链路层的发送数据的大小的,在这个情况

下我们来看,对于来自TCP层的数据,IP会不会进行分片。

 




 
从第一张图看来,应用层的2748个字节在TCP层就进行了分段,分层了两个TCP段,一个1460字节,一个1288字节。那么到IP层的时候,自然就不会在进行分片了。

 




 
从第二张图片看出,在这两个TCP分段中,在序号3处,IP的头部字段(Don ' t Fragment) 被设置了,用于告诉IP层不要对该数据进行分片。

 

而对于MSS大小的协商,我们可以从下面这张图片看到,下面的图片是TCP CLIENT发出的第一个SYN TCP分段:

 

 

 

对于UDP来说,假设我们要发送的一个UDP数据包大小为1600个字节,那么在实际上通过UDP/IP分发出去的时候,会不会进行分片呢? 看如下的图片:



 
 从上面的图片可以看出,我们发送的数据包的大小为1600字节(序号1处),在UDP层,长度为1608字节(序号2处),这里的8个字节是UDP的头部字段的长度, 到了IP层(序号3处),我们可以清楚的看到IP对UDP数据包进行了分片,一个大小为1480字节,一个为128字节。

IP数据包沿着协议栈进入数据链路层的时候,如果IP数据包的长度超过MTU,则会产生分片操作,

每个分片后的IP数据报是相互独立的,它们在中间路由器可能会再次进行分片,分片重组是在到

达目的主机后进行的。IP数据报的重组对于传输层是透明的。

 

通常,不建议IP数据报被进行分片。当IP数据报被分片后,到达目的主机后会对IP数据报分片进行

重组,进而组成一个IP数据报,如果其中缺少一个IP分片,也就缺少了,因为IP没有超时重传机制,

这是由上层协议支持的。而对于上层协议(如TCP),发现少了IP数据报不完整,会进行整个IP数据报

的重传,而不是只重传其中某一个分片。

 

TCP应试图避免IP分片,当对于应用程序来说几乎不可能强迫应用程序发送一个需要进行分片的长报

文段。这是因为在TCP连接初期,在发送SYS请求同步时,会在TCP可选字段中告诉对方自己的MSS大小

的(以太网中,最小重组大小为535),IPv4版本,mss = MTU - 20 -20,故IP数据报是不可能超出MTU的

大小的,分片也就是不可能的。

 

UDP很容易导致IP分片,如果使用了可靠的UDP传输机制,那么应该避免UDP的分片,一旦某个分片丢失,

将导致整个IP数据报的重传。通常在用UDP传输数据的时候,为了避免产生分片:

  UDP数据的大小 = MTU - 20 - 8

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值