网络流量监控工具 网络流量控制


TCP流量控制主要是通过基于接收方确认的滑动窗口机制和发送方基于网络情况的拥塞控制算法来实现的!
TCP Traffic Control TCP流量控制主要涉及滑动窗口、拥塞控制算法、RTT(往返时间)、RTO(重传超时)计算等 。
滑动窗口通常认为是接收方反馈给发送方的流量和重传控制(不考虑网络); 拥塞控制算法通常认为是发送方的流量控制算法(考虑网络时延丢包等); RTT计算会影响到RTO计算及影响某些拥塞算法运行结果; RTO计算会涉及到超时重传定时器设置 。滑动窗口 滑动窗口(Sliding window)是一种机制 , 接收方在数据传输过程中向发送方宣告窗口 , 然后发送方根据窗口决定一次发送多少数据 。它本质上是ARQ(自动重复请求、停止协议等) 。).一方面 , 滑动窗口通过使用来自接收方的确认消息反馈的窗口大小来控制每个分组的数量 。另一方面 , 数据帧的重传是根据接收方确认消息的确认号来判断的 , 滑动窗口只是通过接收方反馈的信息来控制流量 , 没有考虑网络带宽延迟等因素 。
有两种ARQ:连续ARQGo-Back-N和选择性ARQ重复 。Go-back-n和选择性重复在TCP中用作可选实现 。Go-back-N和选择性重传的区别在于 , Go-back-N一次包传输只有个定时器 , 如果中间有丢包 , 则丢包后的所有包都需要重传 , 选择性重传一次包传输的包数需要与相同 。如果中间有丢包 , 则只重传丢失的包 。简单来说 , Go-back-N消耗更多的网络带宽 , 选择性重复消耗更多的计算资源 。
两个ARQ滑窗发送过程可以参考以下网站的动画:https://www2.tkn.tu-berlin.de/teaching/rn/animations/gbn _ Sr/
TCP滑动机制的原理可以简单描述为:TCP发送方包含一个发送窗口 , 按照序列号发送数据包 , TCP接收方根据收到的数据包回复确认包 , TCP发送包根据收到的确认包中通告窗口的反馈动态调整发送窗口的大小 , 滑动窗口向右移动发送后续数据包 。
如下面tcpipguide网站的TCP滑动窗口所述 , TCP发送方的发送缓冲区分为已发送确认、已发送未确认、未发送接收方就绪、未发送接收方未就绪四个区域 , TCP接收方的接收缓冲区分为已接收确认、未接收、允许发送、未接收生成方不得发送三个区域 。
Linux内核4.x中滑动窗口代码的例子与tcpipguid网站中的描述大体一致:
static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 ack, u32 ack_seq){ struct tcp_sock *tp = tcp_sk(sk); int flag = 0; u32 nwin = ntohs(tcp_hdr(skb)->window); if (likely(!tcp_hdr(skb)->syn)) nwin snd_wnd != nwin) { tp->snd_wnd = nwin; tp->pred_flags = 0; tcp_fast_path_check(sk); if (!tcp_write_queue_empty(sk)) tcp_slow_start_after_idle_check(sk); if (nwin > tp->max_window) { tp->max_window = nwin; tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie); } } } tcp_snd_una_update(tp, ack); return flag;} RTT&RTO计算 TCP流量控制中RTT和RTO的计算是一个非常重要的问题 。在ARQ , 丢包需要超时重传 , 超时的设置会涉及RTO , 太短了(srtt _ us如果(srtt!= 0){ m-=(srtt > > 3);srtt+= m;if(m < 0){ m =-m;m-=(TP-> mdev _ us > > 2);if(m > 0)m > > = 3;} else { m-=(TP-> mdev _ us > > 2);} TP-> mdev _ us+= m;if(TP-> mdev _ us > TP-> mdev _ max _ us){ TP-> mdev _ max _ us = TP-> mdev _ us;if(TP-> mdev _ max _ us > TP-> RTT var _ us)TP-> RTT var _ us = TP-> mdev _ max _ us;} if (after(tp->snd_una , TP-> RTT _ seq)){ if(TP-> mdev _ max _ us < TP-> RTT var _ us)TP-> RTT var _ us-=(TP-> RTT var _ us-TP-> mdev _ max _ us)> > 2;TP-> RTT _ seq = TP-> snd _ NXT;TP-> mdev _ max _ us = TCP _ RTO _ min _ us(sk);} } else { srtt = m mdev _ max _ us = TP-> RTT var _ us;TP-> RTT _ seq = TP-> snd _ NXT;} tp->srtt_us = max(1U , srtt);} Linux内核4.x中的RTO计算代码:
void tcp_set_rto(struct sock *sk){ const struct tcp_sock *tp = tcp_sk(sk); inet_csk(sk)->icsk_rto = __tcp_set_rto(tp); tcp_bound_rto(sk);}static inline u32 __tcp_set_rto(const struct tcp_sock *tp){ return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us);} 拥塞控制算法 由于滑动窗口只考虑接收方的接收能力而不考虑网络因素 , 网络带宽是共享的 , 网络时延是抖动的 , 网络的变化带来的问题势必造成整个系统的崩溃 。这就好比两个火车站运输货物 , 只考虑火车站的容量 , 不考虑铁路轨道的承载能力 。不管发多少趟车 , 都有可能被堵在轨道上 , 甚至导致轨道系统瘫痪 。
拥塞控制算法是发送方根据当前网络情况调整包速率的流量控制机制 。TCP中的拥塞控制算法发展至今 , 从经典的reno到近年来google提出的bbr , 不断有新的拥塞控制算法提出 , 拥塞控制也形成了下面的RFC 。RFC 5681https://datatracker.ietf.org/doc/html/RFC 5681以linux内核为例 。最新的内核版本实现了十多种拥塞控制算法 , 包括一些较新的算法(如bbr) 。早期版本的linux内核使用reno , linux 2.6.8以后默认采用bic算法 , linux 2.6.19以后默认采用cubic算法 。目前linux 5.x仍然默认使用立方算法 , windows也支持多种拥塞控制算法 。目前Windows S11也默认使用立方算法 。


推荐阅读