TCP协议作为一个可靠的面向流的传输协议,其可靠性和流量控制由滑动窗口机制保证,而拥塞控制则由控制窗口结合一系列
的控制算法实现。
一、滑动窗口机制
对于TCP协议的精髓–滑动窗口
机制
,自己理解有两点:
1. “窗口”对应的是一段可以被发送者发送出去的字节序列,其连续的范围称之为“窗口”;
2. “滑动”则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序“滑动”。
在引入一个例子来
说这个协议之前,我觉得很有必要先了解以下前提:
1. TCP协议的两端分别为发送者A和接收者B,由于是全双工协议,因此A和B应该分别维护着一个独立的发送缓冲区和接收缓
冲区,由于对等性(A发B收和B发A收),我们以A发送B接收的情况作为例子;
2. 发送窗口是发送缓存中的一部分,是可以被TCP协议发送的那部分,其实应用层需要发送的所有数据都被放进了发送者的
发送缓冲区;
3. 发送窗口中相关的有四个概念:
已发送并已收到确认的数据:不再发送窗口和发送缓冲区之内;
已发送但未收到确认的数据:位于发送窗口之中;
未发送但
允许发送的数据:位于
发送窗口之中;
未发送并且暂时不
允许发送的数据:位于
发送窗口外发送缓冲区内;
4. 每次成功发送数据之后,发送窗口就会在发送缓冲区中按顺序向前移动,将新的数据包含到发送窗口中准备发送。
例子:
TCP建立连接的初始,接收端B会告诉发送端A自己的接收窗口大小,比如为‘20’:则A会构造自己的发送窗口也为20,图
中
字节31-50为A的发送窗口。
A发送11个字节后,发送窗口位置不变,B接收到了乱序的数据分组:
只有当A成功发送了数据,即发送的数据得到了B的确认之后,才会移动滑动窗口离开已发送的数据;同时B则确认连续的数据
分组,对于乱序的分组则先接收下来,避免网络重复传递:
二、流量控制
流量控制方面主要有两个要点需要掌握。一是TCP利用滑动窗口实现流量控制的机制;二是如何考虑流量控制中的传输效率。
1. 流量控制
所谓流量控制,主要是接收方发送信息给发送方,使其不要发送数据太快,是一种端到端的控制。主要的方式就是返回
的ACK中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送:
这里面涉及到一种情况,如果接收端B已经告诉发送端A自己的缓冲区已满,于是A停止发送数据;等待一段时间后,B
的缓冲
区出现了富余,于是给A发送报文告诉A我的rwnd(接收窗口大小)为400,但是这个报文不幸丢失了,于是就出现A
等待B的通
知||B等待A发送数据的死锁状态。处理这个问题的机制是TCP引入的持续计时器(Persistence timer),当A收到
对方的零窗口通
知时,就启用该计时器,定时时间到则发送一个1字节的探测报文,对方会在此时回应自身的接收窗口大小,
如果结果仍未0,则重
设持续计时器,继续等待。
2. 传递效率
一个显而易见的问题是:单个发送字节单个确认,和窗口有一个空余即通知发送方发送一个字节,无疑增加了网络中的
许多不必要的报文(请想想为了一个字节数据而添加的40字节头部吧!),所以我们可选的原则有两种:
:尽可能一次多发送几个字节;
:接收方窗口空余较多的时候通知发送方一次发送多个字节。
对于–
尽可能一次多发送几个字节
—
:尽可能一次多发送几个字节
我们广泛使用Nagle算法,即:
1. 若发送应用进程把要发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面
的字节先缓存起来;
2. 当发送方收到第一个字节的确认后(也得到了网络情况和对方的接收窗口大小),再把缓冲区的剩余字节组成合适大
小的报文发送出去;
3. 当需要发送的数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段;
对于–
接收方
窗口空余较多的时候通知发送方一次发送多个字节
—
我们的做法是让接收方等待一段时间,或者接收方获得足够
的空间容纳一个报文段或者等到接收缓存区有一半空闲的时候,再通知发送方发送数据。
三、拥塞控制
网络中的链路容量(双绞线等)和交换结点(路由器等)的缓存和处理机都有着工作的极限,当网络的需求超过它们的工作
极限时,就出现了拥塞。
拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。常用的方法就是:
1. 慢开始、拥塞控制;
2. 快重传、快恢复。
一切的基础还是慢开始,这种方法的思路是这样的:
1. 发送方维持一个叫做“
cwnd(拥塞窗口)
”的变量,该变量和接收端的接收窗口共同决定了发送端的发送窗口;
2. 当主机开始发送数据时,避免一下子将大量字节注入到网络,造成拥塞或者增加拥塞,首先选择发送一个1字节的探
测
报文;
3. 当收到第一个字节的数据的确认后,就发送2个字节的报文;
4. 若再次收到2个字节的确认,则发送4个字节,依次递增2的指数级;
5. 当达到一个提前预设的“
ssthresh(
慢开始门限)”时,比如24:即一次发送24个分组,此时遵循下面的条件判定:
*1. cwnd < ssthresh, 继续使用慢开始算法;
*2. cwnd > ssthresh,停止使用慢开始算法,改用拥塞避免算法;
*3. cwnd = ssthresh,既可以使用慢开始算法,也可以使用拥塞避免算法;
6. 所谓拥塞避免算法就是:每经过一个RTT(往返时间)就把发送端的拥塞窗口+1,即让拥塞窗口缓慢地增大,按照线
性规律增长;
7. 当出现网络拥塞,比如丢包时,将
ssthresh(
慢开始门限)设为原先的一半,然后将cwnd
(拥塞窗口)
设为1,执行
慢开始算法(较低的起点,指数级增长);
上述方法的目的是在拥塞发生时循序减少主机发送到网络中的分组数,使得发生拥塞的链路或路由器有足够的时间把队列中
积压的分组处理完毕。
慢开始和拥塞控制算法常常作为一个整体使用,而快重传和快恢复则是为了减少因为拥塞导致的数据包丢失带来的重传时
间,从而避免传递无用的数据到网络。
快重传的机制是:
1. 接收端需建立这样的机制,如果一个包丢失,则对后续的包继续发送针对该包的重传请求;
2. 一旦发送端接收到三个一样的重传请求,就知道该包丢失,立刻重传该包;
3. 此时发送方开始执行“快恢复”算法:
*1.
ssthresh(
慢开始门限)减半;
*2. cwnd
(拥塞窗口)
设为慢开始门限减半后的数值;
*3. 执行拥塞避免算法(高起点,线性增长);