分类: LINUX
2011-05-06 16:06:54
超时与重传
最近没事,好好看下TCP 超时与重传,主要是参考TCP 卷1 2 ,TCP 如今在linux 2.6上实现许多细节变化较多,但基本机制或者说思路没有变化,变化的一些具体的算法上,更能适应今天的的高速网络,比如新的算法可以更灵活的更好的适应今天较小的网络时延,本人在这方面也是刚入手,准备把基本的机制搞透以后再去研究一下当今linux 2.6 TCP 内核实现,关于此CU 上有人出了一本书,名字关于Linux 2.6 Tcp 剖析类似的,是很好的学习材料。
-------------预备知识-------------
在以太网中:
链路层 MTU :最大传输单元 1500
网络层 MSS :最大报文段长度 1460 ,默认536字节。
三次握手时
连接 syn +
-------------正文-------------
场景模拟:
net1<---->route1<---->route2<----->xxx.......<---->net2
1:中间某些路由速率较慢,需要缓存分组,耗尽了存储空间,这样会出现问题 ?
丢包! 重传!
后果:降低网络带宽利用率
2:怎样解决这样的问题?
因此有慢启动算法。观察数据进入网络的速率应该与另一端返回确认的速率相同而进行工作。
3: 慢启动实现
发送方增加了一个窗口叫:拥塞窗口(cwnd),建立连接时初始化为一个报文段大小,(实际上是2个)每收到一个ACK , 拥塞窗口就增加一个报文段。发送方开始发送一个报文段,然后等待ACK,当收到该ACK时,拥塞窗口增加到2,即可以发送二个报文段,当收到这两个的ACK时,拥塞窗口增加到4,可以发送4个报文段,----指数增加
Ø cwnd大小指对端的MSS,连接时得知,如果连接时未得到此大小,默认是536,linux 未验证
Ø 发送时,MIN(cwnd,通告窗口?) 取二者最小值。
-------------滑动窗口-------------
滑动窗口:发送方和接收方缓存大小,又叫插口缓存。4.2BSD 默认大小为2048,4.3增加到4096字节,sunos 4.1.3是4096字节,solaris 2.2 bsd 4.4 Aix 3.2 是8192字节或更大。
每次发送一个TCP数据报,都要构建TCP首部,这时,会调用tcp_select_window选择窗口大小,窗口大小选择的基本思想是接收缓存剩余空间大小的3/4,但是不能超过rcv_ssthresh的大小。每次发送一个TCP数据报,都要构建TCP首部,这时,会调用tcp_select_window选择窗口大小,窗口大小选择的基本思想是接收缓存剩余空间大小的3/4,但是不能超过rcv_ssthresh的大小。
???增加二个图:p212 发送, 自己画或网上找个接收的
1 2 3 4 |5 6 7 8 |9 10 11 12|13 14 15 ….
|<---- win xxxx 通告窗口--->| ack 1987 win xxx 字样
5:拥塞避免算法?
此算法假定分组到损坏引起的丢失是非常少的(小于1%),因此分组丢失就意味着某处网络发生了拥塞。
分组丢失的依据是:发生超时和接收到重复的确认
此算法作用:处理丢失分组的方法。
拥塞避免算法要求每次收到一个确认时将cwnd 增加1/cwnd。----加性增长
6:慢启动和拥塞避免
拥塞避免和慢启动是两个目的不同,独立的算法。但是关系密切,当发生拥塞时,我们希望降低分组进入网络的传输速率,于是会调用慢启动。
每个连接中拥塞避免和慢启动关联二个变量:拥塞窗口cwnd 和慢启动门限ssthresh。
具体工作如下
1) 对于一个连接,初始化cwnd为一个(实际2个报文段大小),ssthresh 为65536个字节。
2) TCP 输出 MIN(cwnd,接收方通告窗口)。MIN(cwnd,接收方通告窗口)又叫当前窗口。
3)当发生拥塞时(发生超时或3次重复确认),ssthresh =1/2*(当前窗口),但至少2个报文段。如果是超时引起了拥塞,则会启动慢启动(cwnd =1个报文段)
4) 当新的数据被对方确认时,就增加cwnd。
If (cwnd<=ssthresh)
则在慢启动,cwnd+=ACK 个数
Else
则在拥塞避免, cwnd+=1/cwnd
慢启动一直持续到拥塞发生时所处的位置(ssthresh)才停止,然后转为执行拥塞避免。
7:快速重传与快速恢复
失序报文段:TCP 立即产生一个ACK(重复的ACK),此ACK不会被迟延。比如 收到:1 3 2 4 ack 1 ack 1 ack 3 ack 4
重新排序只可能产生1~2个重复ack ,如果一连串收到3或以上重复Ack,就非常可能是一个报文段丢失了,于是我们就重传丢失的报文段,无需等待超时器溢出, 这就是快速重传,接下来执行不是慢启动而是拥塞避免算法,这就是快速恢复算法。
快速重传快速恢复算法过程:
1)当收到第3个重复的Ack时,将ssthresh 设置为1/2*cwnd。重传丢失的报文段。cwnd = ssthresh +3*报文段大小
2)每次收到另一个重复的ack 时,cwnd+=1,并发送一个分组(如果允许)
3)当下一个确认新数据的ACK到达时,设置cwnd 为ssthresh(第一步设置的值 ),此时cwnd =ssthresh(小于等于慢启动),收到1个ack,所以cwnd=+=1,然后进入拥塞避免。
² 第1 、2 步是快速重传,第3步是快速恢复。
图中收到报文段64 、65重复的ack 没有发送数据,这是因为cwnd 和未确认的数据大小的比较的结果。报文段65到达进,cwnd为2048,但未被确认的数据有2304字节。因此不能发送任何数据。当报文段66到达时,cwnd=2560,所以可以发送一个报文段。类似的68,70。(关于这个图我有疑问,怎么画出来?怎么知道服务端应答是对应哪个包?)
个人疑问:
这二个图是卷1中的21章的图,二条红线内4个点就是重传ack过程,但当收到第3个重复的Ack时(也就是第四个点时),书中说将ssthresh 设置为1/2*cwnd。重传丢失的报文段,cwnd = ssthresh +3*报文段大小。 就是说第四个点cwnd 是变化的。看图21-11 cwnd 确实也是变化的,但图21-10中三次重传这4个点都是一样大小的cwnd? 总之就是按书上说,红线内的第4个点(第3次的重复ack )Cwnd 值 不应与前三个一致?--跟相关人员讨论过,回答说以21-11数据为准 。 也就是应证我的怀疑,21-10图有欠妥。
几个关键词不要混淆
1: 拥塞窗口cwnd 通告窗口 当前窗口
2: 重传 重复的Ack
-------------正文结束-------------
***下面的有待整理,滑动窗口,nagle 算法
问题
1:收到重复Ack ,不一定立即发送丢失包,如果cwnd 允许
2:收到失序报文段,ack 不时延,立即发送。
3:通告窗口会报文段大小的倍数通知 256 512 1024 4096,还是其他数字形式?167,456,872,8654…?
4:21-10 图,红线内,第三次重复ack 到达,cwnd 应减少一半。
Nagle 算法:
如果某个连接需要等待对端的确认,则不允许发送长度小于最大长度的报文段。
发送:
如果由于持续定时器超时,或者有带外数据,强迫TCP执行发送操作,则数据发送。如果接收方的接收窗口已至少打开了一半,则发送数据。――卷2 p686
举例1:
应用进程向某个空闲的连接写入100字节,接着又写入50字节,假定报文段大小为512字节。在第一次写入操作时,收于连接空闲,且tcp 正在清空发送缓存,代码执行,发送一个报文段,带100字节的数据。
在第二次写入50字节时,代码执行,但未发送报文段:50字节不能构成最大长度报文段,连接未空闲(等待第一个的ACK),默认采用nagle算法,t-force 未置位,假定接收窗口4096,50不满足2048,所以50个字节缓存起来,也许会一直等待第一个报文段的Ack。由于对端的可能延时发送ack。最后发送这50字节延时会更长。
ACK 的发送:
ping 192.168.1.x -l 600
IP 分片? ping 测分片
大分组还是小分组?
图:p217