龙空技术网

TCP网络包传输的整个过程

愿从心出发 715

前言:

眼前大家对“java发送tcp数据包方法”大概比较重视,大家都想要知道一些“java发送tcp数据包方法”的相关文章。那么小编同时在网摘上收集了一些关于“java发送tcp数据包方法””的相关文章,希望咱们能喜欢,看官们快快来学习一下吧!

承接上文如何排查网络丢包问题

上文对于网络问题分析的还不够精细,比如有时候网络资源可能没有达到瓶颈,并且没有丢包产生,但这个时候网络传输速率就是很慢或者是有丢包产生了,但是却无法知道丢的是具体哪个包,没有办法知道整个tcp传输过程的具体情况,所以需要一种更加精细的去看网络包传递过程的方法即抓包。

用wireshark去分析上传文件整个tcp的传输过程,

用wireshark提供的高级的图表功能去感受下tcp在整个过程当中所经历的各种阶段。

tcp在整个过程当中所经历的阶段:三次握手、慢启动、拥塞避免、快速恢复、四次挥手。

除了三次握手、四次挥手,其他几个阶段都涉及到了tcp窗口的概念。

tcp的滑动窗口

tcp的发送和接收数据都是通过滑动窗口,在tcp协议里,发送数据的滑动窗口被称为发送窗口;接收数据的滑动窗口,被叫做接收窗口。

发送窗口大小会影响发送数据的大小,那它的大小是受制于两个因素:

第一个是对端接收窗口的大小,第二个是拥塞窗口的大小,取这两个窗口大小的最小值。

tcp的发送窗口,如果只受限于对端接收窗口大小的话,这种情况在局域网其实是没有什么问题的,但是在广域网里,数据传输过程中很有可能是经过很多的路由器或者是交换机,如果中途设备网络处理能力变差之后,即使对端接收窗口的能力很大,但是可能数据包在中途的时候就被丢掉了,所以tcp得有一种功能是能够感知网络的这种拥塞阻塞的情况,并根据这种情况的好坏,去调整发送窗口的大小,所以这个功能就是拥塞窗口的功能。

拥塞窗口是如何衡量这种拥塞情况的?

当发生重传的时候,这个拥塞窗口就会认为此时的网络发生了拥塞的情况。

重传是分为快速重传和超时重传,拥塞窗口会根据这两种重传方式作出不同的策略。

超时重传

指的是数据包在发送数据到对端的时候,本来是要接受到一个ack标志的数据包回来,但如果在一定时间以内发送端没有接受到对端的ack包,那么发送端就会认为数据包丢掉了,那它会重新去传递相同的数据包到对端,这种相当于定期触发的这种重传,被称为超时重传。

快速重传

当每次都要等到超时时再去重传,会增大端与端的时延,所以快速重传就认为如果是收到了对端三次重复的ack,那么就认为ack的这个包丢掉了,所以会马上对丢掉的包去进行重传,而不用等待定时器超时之后再去触发重传的动作。

对端重复ack是如何产生的呢? 因为tcp发包不是一个一个发的,而是一组一组的发到对端,所以其中如果某个包丢失了,那对端接收到的大于丢失包序号的包,那回应的ack将会是丢失前最大的ack序号。

比如发一组数据包到这个服务端,如果2号包丢失之后,那3、4、5号包还是有机会到达服务端的,

那服务端看到了3、4、5号包,但是又对比起自己的ack的序号,它发现还没有对2号包去进行ack,所以它对3、4、5号包的这种ack的序号就是2,所以当连续的收到三个ack 2之后,那客户端就会对2号包去进行一个重传的动作,这就是快速重传。

拥塞窗口对这两个重传是怎么进行不同策略的?

拥塞窗口它会经历三个阶段:慢启动、拥塞避免、快速恢复 。

依次来看一下,当连接建立的时候,每次收到一个ack,那么拥塞窗口能够去发送的最大mss(即一个tcp包的最大发送的字节数)就会翻倍,当这个最大发送的数据达到了慢启动的阈值(这个是可以通过内核去配置的),就会进入第二个阶段,叫作拥塞避免阶段。在拥塞避免阶段,拥塞窗口的增长速率,就没有慢启动阶段那么快了,它的策略是每经过一个往返延迟,拥塞窗口就会增长mss的大小,无论是慢启动还是拥塞避免阶段,如果期间碰到重传的这种行为的时候,那么拥塞窗口,会有选择性的去进入慢启动阶段还是一个快速恢复阶段。

快速恢复阶段是为了避免每次碰到拥塞时都会进入慢启动阶段而产生的,因为每次如果重传都进入到了慢启动阶段,那传输的效率会急剧的降低,所以快速恢复采用的策略是当遇到快速重传的时候,让拥塞窗口减半,然后它的mss的增长方式是和拥塞避免的增长方式是一样的,采用低斜率的线性增长的方式。然后遇到超时重传的时候,其实整个过程依然是会进入到慢启动阶段。这样的话,就能根据不同的重传,采用这种不同的缩小拥塞窗口的策略,来达到限制发送窗口的数据发送量的大小的目的。

在上传文件的过程当中,

tcp发送数据的接收窗口、发送窗口是如何变化的?

这里使用了wireshark的tcp stream graphs这种高级图表功能去看,首先来看一下慢启动阶段的一个特点,就是能够让发出去的包在特定时间以内能够呈现指数级增长,因为每收到一个数据包的ack,它会让拥塞窗口发出去的mss达到一个翻倍,所以它是一个指数级的增长。

这里用tcp的时序图stevens来看这种增长变化,x轴是时间,y轴是发出去包的seq number,可以看到,在前面0-5秒,特别是接近五秒这段时间,它的一个seq number的增长速率是相当大的,也是十分陡峭的,然后在慢启动之后,它的一个seq number其实是小于之前点的,那为什么会出现这样的点?是因为发生了重传,发生重传就是发送之前发出去过的包,所以seq number会小于之前发送出去的seq number。并且在这个慢启动之后,有好几波这种低于之前发出去的seq number的情况,所以这里猜测:在第一次慢启动之后,并且达到峰值之后,网络出现了这种拥塞的情况,导致发生了这种重传的现象,并且在后续的一段时间以内,这种重传的现象还时不时的在发生,说明此时网络真的是属于一种很拥塞的情况,然后在7.5秒之后,网络的情况就渐渐好转了,然后丢包的现象就开始好起来了。在5.5到7.5秒的期间,的确是有很多这种超时重传的现象,也验证了刚刚的猜想。

在五秒的时候发生了一个拥塞,这里对上传文件进行抓包,所以看一下这个拥塞到底是对传输速率有怎样的影响?

在wireshark里提供了图表的功能看整个过程的传输速率,

I/O Graphs就是看传输速率的图表,以100毫秒的间隔去看整个过程传输数据的变化,可以看到,在发生拥塞之前,传输速率的增长依然是呈指数级别的增长,然后在发生重传之后,速率在急剧的下降回来,下降到0之后,又开始呈现指数级别的增长,这里就和刚才所说的,碰到这种超时重传之后,会进入一个慢启动的阶段,慢启动阶段的特点就是能让发出去的包呈现一种指数级别增长。

第二次慢启动阶段所达到的峰值还没有第一次那么高的时候,又下降,但是这个下降的坡度没有第一次那么低,所以有可能这里是在进行一个快速恢复的阶段。

快速恢复的阶段碰到的是快速重传,碰到快速重传之后,传输数据就下降为之前的一半,然后进入一个快速恢复的阶段,快速恢复阶段,mss一直增长的,坡度是在一个固定斜率的直线,所以也和传输速率图是极其吻合的,所以很有可能这里发生了一个快速重传。

然后关于传输速率的影响,除了拥塞带的影响 其实还有接收窗口所带来的影响。

如果接收窗口太小了,传输速率是提升不上去的,那么如何肯定传输速率下降了是由于网络的阻塞而不是接收窗口所带来的影响呢?

其实有两点,第一点在tcp的时序图stevens找到了对应速率下降的时间点,并且看对应时间点包的传输情况是有发生大量超时重传的,说明的确有丢包产生,说明当时的网络状况并不好。

第二点通过wireshark和window scaling去看接收窗口随时间的一个变化情况,

可以看到绿色这条线是代表的接收窗口的大小,蓝色这种bytes out就是经常说的在途数据,在途数据是指已经发送但是还未被确认的数据,在途数据越多,说明发送端发送的数据就越多。

整个过程,可以看到接收窗口其实是在不断增长的,并且增长到有4M之后,没有变小,一直是稳定的持续到4M这个界限,然后反而是发送端的一个在途数据在达到峰值之后,就一直变小,并且在后续的这段抓包时间内,都没有达到接收窗口的饱和,所以断定了这里传输速率的下降其实是由于当时网络真的是不好,不是由于接收窗口这种大小导致的。

那如果是由于接收窗口大小导致的,那这个window sacaling所展现出来图应该是怎么样的?

Site Out比较贴合4M的这个直线,而不是中间留了那么一大片空白的地方,并且在wireshark中可以看到很多tcp window full这种包,就说明你的接收窗口可能是一直处于一种饱和的状态,有可能接收窗口太小了,这个时候得调大接收窗口的数量。

调整接收窗口的大小的策略

接收窗口受tcp里面的receive buffer大小的影响,reveive buffer是由内核去根据系统可用内存的情况和内核参数net.ipv4.tcp_rmem参数动态的去调节,tcp的receive buffer的大小,不完全的等于接收窗口的大小,是用reveive buffer的大小去除以2的指数次方的大小分配给应用,这个参数也是可以去通过内核文件去改配置的。

就比如这个scale的大小是2的时候,那就会有1/4的receive buffer是给应用的,然后其余的3/4才会真的用于接收窗口。

如果表达tcp窗口的大小值,在tcp协议报文中留意window字段,在抓到包里面可以看到,window字段的表达式其实只有16位,16位就决定了要表达这个窗口的最大值,只能表示位64kb,那如果tcp窗口大于64kb的时候 ,就要用另外一个字段window scaling,这个字段能够去和window这个字段去进行乘积,同样的去通过2的scale次方进行一个乘积,然后得到的最终结果,才是实际的接收窗口的大小。

window scaling字段会在握手的时候就告诉给对方,如果是接收窗口是瓶颈的话,那可能要调大接收方的receive buffer或者是tcp window scaling的参数。

本文介绍了tcp stream graphs宏观的分析了文件上传过程当中tcp的传输过程,用的是wireshark里面提供这种图表的功能。

标签: #java发送tcp数据包方法