- 滑动窗口,接收方通过通告发送方自己的可以接受缓冲区大小(这个字段越大说明网络吞吐量越高),从而控制发送方的发送速度。滑动窗口的存在是为了防止接收方过载。它规定了发送方此刻能够发送的最大数据量
但滑动窗口只考虑接收方的缓冲区,对网络链路的拥塞程度则无能为力。因此,TCP 还维护了 拥塞窗口( congestion window ),根据链路的拥塞程度来约束发送速度。
拥塞窗口跟滑动窗口类似,同样规定了发送方此刻能够发送出去的字节数,只不过它通过评估网络链路的拥塞程度,并由一定的算法计算而来的。
拥塞窗口可缩写为 cwnd ,通常以 TCP 报文段为单位,表示还能发送多少个段出去。由于 最大报文段大小 缩写为 MSS ,有时也会以 MSS 为单位来讨论。
- 拥塞窗口(congestion window)是任何时刻内确定能被发送出去的字节数的控制因素之一,是阻止发送方至接收方之间的链路变得拥塞的手段。他是由发送方维护,通过估计链路的拥塞程度计算出来的,与由接收方维护的接收窗口大小并不冲突。
当网络链路比较顺畅时,拥塞窗口逐步增大,发送速度也就逐步提升;当网络链路发生拥塞时,拥塞窗口快速减小,发送速度急踩刹车,避免进一步压垮网络。
拥塞窗口跟滑动窗口并不冲突,前者避免压垮网络链路;后者则保证不打爆接收缓冲区。
拥塞控制
我们希望 TCP 能够根据网络链路的实时状态,自动调整发送速度,这就是 TCP 协议的 拥塞控制( congestion control )机制。拥塞控制机制细节很复杂,但原理却出奇的简单:
- 维护拥塞窗口,限制数据发送量;
- 根据网络当前状态,实时调节拥塞窗口:
- 如果长时间未收到 ACK 而发生数据重传,说明网络可能拥塞,缩小拥塞窗口,降低发送速度;
- 每收到一个有效 ACK 都增大拥塞窗口,提高发送速度,因为这通常意味着网络状态良好;
/* Can at least one segment of SKB be sent right now, according to the
* congestion window rules? If so, return how many segments are allowed.
*/
static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp,
const struct sk_buff *skb)
{
u32 in_flight, cwnd, halfcwnd;
/* Don't be strict about the congestion window for the final FIN. */
if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) &&
tcp_skb_pcount(skb) == 1)
return 1;
in_flight = tcp_packets_in_flight(tp);
cwnd = tcp_snd_cwnd(tp); //tp->snd_cwnd , Sending congestion window
if (in_flight >= cwnd)
return 0;
/* For better scheduling, ensure we have at least
* 2 GSO packets in flight.
*/
halfcwnd = max(cwnd >> 1, 1U);
return min(halfcwnd, cwnd - in_flight);
}
static inline unsigned int tcp_left_out(const struct tcp_sock *tp)
{
return tp->sacked_out + tp->lost_out;
}
/* This determines how many packets are "in the network" to the best
* of our knowledge. In many cases it is conservative, but where
* detailed information is available from the receiver (via SACK
* blocks etc.) we can make more aggressive calculations.
*
* Use this for decisions involving congestion control, use just
* tp->packets_out to determine if the send queue is empty or not.
*
* Read this equation as:
*
* "Packets sent once on transmission queue" MINUS
* "Packets left network, but not honestly ACKed yet" PLUS
* "Packets fast retransmitted"
*/
static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp)
{
return tp->packets_out - tcp_left_out(tp) + tp->retrans_out;
}
ref
tcp - TCP之拥塞窗口_个人文章 - SegmentFault 思否
https://zh.wikipedia.org/wiki/TCP%E6%8B%A5%E5%A1%9E%E6%8E%A7%E5%88%B6