最大传输单元
网络包在网络上传输是对网络包的大小有限制的。其值成为MTU,即最大传输单元,一般而言,网络中的MTU是 1500 字节,一个大于1500 字节的包进入到 MTU 为1500 字节的网络中就会被丢弃或者切分。被丢弃意味着传输的彻底失败(重传还是会失败)
正是由于这个原因,在一次通信过程中,双方会将自己的MSS(Maximum Segement Size)告诉对方。MSS加上TCP的头和IP头,就是MTU的大小了。
MTU是选最小的那个的。
服务器声明自己的MSS是1460,那么就意味着它的MTU是 1460+20+20 = 1500
TCP的三次握手
TCP建立需要三次握手这个就不用多说了,众所周知,tcp提供的是有序的传输,所以每个数据段都会标上一个序号。当接受方收到乱序的包的时候,有了序号就可以重新进行排序。
seq
序号就是seq
seq不需要知道起始值是怎么算的(wireshark会优化显示起始值是0),但是需要知道seq的增长方式。
一个seq号的大小是上一个数据段的seq和数据包长度相加而来的
如一个包的1号包是 seq=3681,len=1448,那么它的2号包的seq=3681+1448=5129.
这里有个特殊的地方是三次握手和四次挥手,这些阶段的数据包就算len=0 ,也是会+1,正常传输阶段如果是传ack包,len=0的话。那就是seq=seq+0.
ack
ack是确认包,意思是对方可以接着发包了,
比如 A发送了 “Seq:x Len:y” 的数据给 B,那么B会回复确认包 x+y 。这以为着它接收到了x+y之前的所有字节。而B的ack其实就是A的下个包的seq。
TCP的握手阶段
TCP窗口
如果有大量的数据要发送,这样的一发一回的方式会很低效。
高效的方式是,一口气将所有的包都发出去,然后一起确认,也就是只确认一次。
但是为了防止对方一时无法接受全部的数据,对方会回一个接受缓存(窗口)。一次性可以发送多少数据量就是窗口。
- 这里需要注意无论窗口有多大,一个数据包的大小是不会超过MSS的。一般窗口的大小会是数个MSS的大小。
- win 是指的接受窗口,而滑动窗口中的概念发送窗口,其实是虚的,并不在TCP的包头中可以体现出来。
那么接受的窗口有多大呢,原本的最大窗口是65535字节,但是互联网的发展导致65536太小了,所以在tcp option 中出现了 windows scale,如上图就是7,那就意味着 接受窗口要 乘以 2的7次方。也就是65535 * 128 字节。
TCP 慢启动+拥塞避免+重传(RTO)
在网络传输的过程中,最忌讳的就是网络堵塞。如果发的数据包大多,可能就会导致堵塞。而导致网络堵塞的数据量就是堵塞点了,发送数据的一方希望将发送窗口控制在堵塞点以下。但是问题是,很难确认网络设备的堵塞点是多少。
逐次增加发包量,直到发生堵塞,从而探知堵塞点
1.连接刚开始建立的时候,堵塞点会设的很小,只有2-4个MSS大小。
2.发出去的包都得到确认,证明没有达到堵塞点,这就表示没有到达真正的堵塞点,堵塞点可以再设大一些,RFC的建议是x2 。即4个包发出去了,都没问题,那么堵塞点就 4x2=8 个MSS。由于基数很小,所以整个过程还是比较慢的,所以叫做慢启动。
- 慢启动经过一段时间了,假设的堵塞点也越来越大,可能触碰真实的堵塞点的可能性也在变大。这时候不能再使用翻倍的慢启动方法了,比如当假设的堵塞点达到16MSS ,还没有达到真正的堵塞点。那么RFC建议,堵塞窗口每次+1. 如16+1 = 17MSS,17+1=18MSS。这个过程称作 避免拥塞阶段 。而由慢启动转变成避免拥塞阶段的这个点就是 临界窗口值。(临界窗口值的取值比较复杂,RFC 2001 建议,把临界窗口值定义为发生丢包时拥塞窗口的一半大小)
慢启动
无论是慢启动还是避免拥塞阶段,拥塞窗口(堵塞点)都是在逐渐增大,也总会碰到拥塞点(如果达到接受窗口了,还没达到拥塞点,那也没办法...) - 发生堵塞。发出去的包得不到确认了。包丢了,只能重传了。这个过程成为超时重传。而重传从发出原始包到重传该包的这段时间称为RTO。发生了堵塞后,RFC建议将拥塞窗口降到1MSS。重新开始一遍慢启动。
可见重传是很降低性能的,不仅需要等待ROT时间,还需要将拥塞窗口下降到1MSS。
重传分两种
1.超时重传:RTO时间没有受到回复包导致的重传。
2.快重传:连续收到3个Dup Ack 而发生的重传。(一般是可能乱序了,但不严重)
另一种就是快重传了,快重传不会等待ROT,只有受到三个Dup Ack就重传,而且发生快重传后,发生的不是拥塞窗口减为1MSS。而是快恢复,拥塞窗口下降1/2 。
- 针对快重传,其实SACK 很有效。还有NewReno算法。
TCP拥塞控制的各种算法
上面说到了,临界窗口值是慢启动和拥塞保持阶段的一个分界点。那么这个分界点的定义,也有很多方式,简单的如上所说的直接定义为发生丢包时的拥塞窗口的一半大小。
对临界窗口值的定义算法可谓百家争鸣。
-
westwood算法
Saverio认为简单粗暴的将临界窗口值定义为丢包时的窗口大小/2 不科学。他认为应该根据接受方回应的ACK来推算,有多少包已经到达接受方了。而这个带宽大小就是临界窗口值。
从设计理念来看,当丢包很轻微时并不会大幅度减小临界窗口值。传输速度也会得以保持。在无线网络中(非拥塞性丢包环境)就有很大的优势。
在定义拥塞窗口方面也有许多算法,这些算法可能有的比较思路清奇。
-
vegas算法
vegas在定义拥塞窗口时提出了全新的理念。其他的算法都是在丢包后才开始调节拥塞窗口的,而vegas是通过监控网络状态来调整发包的速度。当网络状态良好的时候,数据包的RTT(往返时间)比较稳定,而,这个时候可以增大拥塞窗口,但网络比较繁忙,RTT也会变大,这个时候就要减小拥塞窗口。
延迟确认和Nagle算法
接受方如果在接受大量的数据,而不是发送数据,接受方可能希望尽量少发送一些ACK,等发送方多发一些数据,再发送ACK一起确认。因为一个包的大小TCP包的TCP头和IP头至少40字节,而携带的包体可能为0(ack确认包)。频繁的出现这样的数据包可能就会造成网络带宽的浪费。这就是延迟确认了。
延迟确认
该策略为收到一个包之后暂时没有什么数据要发送给对方,那就延迟等待一段时间(windows默认是200ms)。加入这段时间内恰好有数据要发送,那确认信息和数据就可以在一个包一块发出去了。
延迟确认没有直接提高网络的性能,只是减少了部分的确认包,减轻了网络的负担。
Nagle算法
发出去的数据包在没有被确认之前,又有小数据生成,那就把小数据收集起来,等待凑满了一个MSS或者等待收到确认后再发送。启用Nagle算法也没有直接提高网络的性能,只是提高了传输效率。减轻网络负担。
Nagle算法不是说发送数据包必须要等到凑够1MSS的数据包才发送,如果有确认包的话,不管你有没有凑够1MSS,都是需要发送的。
当Nagle和延迟确认相遇后,可能就会出现性能问题。一个延迟发送ACK回复包,一个没受到ACK,也在等待数据量凑够1MSS。
网友评论