确认应答策略,对每⼀个发送的数据段,都要给⼀个ACK确认应答.收到ACK后再发送下⼀个数据段.这样做有⼀个比较大的缺点,就是性能较差.尤其是数据往返的时间较长的时候.
为了解决低效率传输,引入了滑动窗口批量传输数据
• 窗口大小指的是⽆需等待确认应答⽽可以继续发送数据的最⼤值.上图的窗⼝大小就是4000个字节(四个段).
• 发送前四个段的时候,不需要等待任何ACK,直接发送;
• 收到第⼀个ACK后,滑动窗⼝向后移动,继续发送第五个段的数据;依次类推;
• 操作系统内核为了维护这个滑动窗⼝,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉;
• 窗⼝越⼤,则⽹络的吞吐率就越⾼;
那么如果出现了丢包,如何进⾏重传?这⾥分两种情况讨论.
情况⼀:数据包已经抵达,ACK被丢了.
这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进⾏确认;
情况二:数据包就直接丢了.
• 当某⼀段报⽂段丢失之后,发送端会⼀直收到1001这样的ACK,就像是在提醒发送端"我想要的是1001"⼀样;
• 如果发送端主机连续三次收到了同样⼀个"1001"这样的应答,就会将对应的数据1001-2000重新发送;
• 这个时候接收端收到了1001之后,再次返回的ACK就是7001了(因为2001-7000)接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中;这种机制被称为"⾼速重发控制"(也叫"快重传").
接收端处理数据的速度是有限的.如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继⽽引起丢包重传等等⼀系列连锁反应.因此TCP⽀持根据接收端的处理能⼒,来决定发送端的发送速度.这个机制就叫做流量控制(FlowControl);
• 接收端将⾃⼰可以接收的缓冲区大小放⼊TCP⾸部中的"窗⼝大小"字段,通过ACK端通知发送端;
• 窗⼝大小字段越⼤,说明网络的吞吐量越⾼;
• 接收端⼀旦发现⾃⼰的缓冲区快满了,就会将窗⼝大小设置成⼀个更小的值通知给发送端;
• 发送端接受到这个窗⼝之后,就会减慢自己的发送速度;
• 如果接收端缓冲区满了,就会将窗⼝置为0;这时发送⽅不再发送数据,但是需要定期发送⼀个窗⼝探测数据段,使接收端把窗⼝⼤⼩告诉发送端.
接收端如何把窗⼝⼤⼩告诉发送端呢?回忆我们的TCP⾸部中,有⼀个16位窗⼝字段,就是存放了窗⼝⼤⼩信息;
那么问题来了,16位数字最大表⽰65535,那么TCP窗⼝最大就是65535字节么?
实际上,TCP⾸部40字节选项中还包含了⼀个窗⼝扩⼤因⼦M,实际窗⼝⼤⼩是窗⼝字段的值左移M;
和流量控制一样,都是限制发送方发送数据的速率
流量控制是站在接收方的角度来制约发送方速率的
如果当前接收方处理速度很快,但是中间的通信路径出了问题,某个地方堵车了,发送的速度再快也没有用
针对这种情况,把中间路径经过的所有设备视为一个整体,然后通过“实验”的方式,找到一个比较合适的传输速率,如果按照某个窗口大小发送数据之后,出现丢包,就视为中间路径存在拥堵,就减少窗口大小,没出现丢包就视为路径不存在拥堵,继续增加窗口大小
总之流量控制和拥塞控制谁产生的窗口小谁说的算
拥塞控制的窗口是如何试出来的呢?
如果接收数据的主机⽴刻返回ACK应答,这时候返回的窗⼝可能⽐较⼩.
• 假设接收端缓冲区为1M.⼀次收到了500K的数据;如果⽴刻应答,返回的窗⼝就是500K;
• 但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了;
• 在这种情况下,接收端处理还远没有达到⾃⼰的极限,即使窗⼝再放⼤⼀些,也能处理过来;
• 如果接收端稍微等⼀会再应答,⽐如等待200ms再应答,那么这个时候返回的窗⼝⼤⼩就是1M;
⼀定要记得,窗⼝越⼤,⽹络吞吐量就越⼤,传输效率就越⾼.我们的⽬标是在保证⽹络不拥塞的情况下尽量提⾼传输效率;那么所有的包都可以延迟应答么?
肯定也不是;
• 数量限制:每隔N个包就应答⼀次;
• 时间限制:超过最⼤延迟时间就应答⼀次;具体的数量和超时时间,依操作系统不同也有差异;⼀般N取2,超时时间取200ms;
在延迟应答的基础上,我们发现,很多情况下,客⼾端服务器在应⽤层也是"⼀发⼀收"的.意味着客⼾端给服务器说了"How are you",服务器也会给客⼾端回⼀个"Fine,thank you";
那么这个时候ACK就可以搭顺⻛⻋,和服务器回应的"Fine,thank you"⼀起回给客⼾端