什么是滑窗迭代算法?

JavaScript011

什么是滑窗迭代算法?,第1张

TCP的首部中有一个很重要的字段就是16位长的窗口大小,它出现在每一个TCP数据报中,配合32位的确认序号,用于向对端通告本地socket的接收窗口大小。也就是说,如果本地socket发送一个TCP数据,其32位确认序号是5,窗口大小是5840,则用于告诉对端,对端已经发出的4个字节的数据已经收到并确认,接下来,本地socket最多能够接收从第5个字节开始的5840个字节长度的数据。这是由接收方进行的一种流量控制,接收方通过告诉发送方自己所能够接收数据的大小,达到控制发送方发送速度的目的。

结构体struct tcp_sock中有很多成员数据跟滑动窗口协议相关,需要注意的是这里讲的滑动窗口都是指本地socket的接收窗口。

成员window_clamp表示滑动窗口的最大值,滑动窗口的大小在变化的过程中不能超出这个值。它在TCP连接建立的时候被初始化,被置为最大的16位整数左移窗口的扩大因子,因为滑动窗口在TCP首部中以16位表示,window_clamp太大会导致滑动窗口不能在TCP首部中表示。

成员rx_opt是一个struct tcp_options_received结构体,它有两个成员snd_wscale和rcv_wscale,分别表示来自对端通告的滑动窗口扩大因子(本地发送数据报时需要遵守),和本地接收滑动窗口的扩大因子。snd_wscale从来自对端的第一个SYN中获取。rcv_wscale在本地socket建立连接时初始化,它赋值的原则是使16位整数的最大值左移rcv_wscale后,至少可以达到整个接收缓存的最大值。接收缓存最大值在协议栈中由全局变量mysysctl_rmem_max表示,它是256*(256+sizeof(struct sk_buff))后的值,为107520,但sysctl_tcp_rmem[3]所表示的接收缓存的上限更大,为174760,所以,取后者,这样的话,rcv_wscale的值几乎可以说是固定的,为2。所以window_clamp的值就是 65535 <<2 = 262140。可见,window_clamp的值超出了接收缓存的最大值,但这没有关系,因为在滑动窗口增长的时候,会考虑接收缓存的大小这个因素的。

rcv_wnd表示当前的接收窗口的大小,这个值在接收到来自对端的数据后,会变动的。它的初始值取接收缓存大小的3/4跟MAX_TCP_WINDOW之间的最小值,MAX_TCP_WINDOW在系统中的定义为32767U。然后,还要根据mss的值作一个调整,调整逻辑是:如果mss大于3*1460,则如果当前的rcv_wnd大于两倍的mss,就取两倍的mss作为rcv_wnd的值;如果mss大于1460,则如果当前的rcv_wnd大于3倍的mss,就取3倍的mss作为rcv_wnd的新值;否则,如果rcv_wnd大于4倍的mss,就取4倍的mss作为rcv_wnd的新值,我们的实验环境的mss值为1448(因为tcp首部有12字节的时间戳选项),所以rcv_wnd最后被调整为1448*4=5792。

只有接收方的接收窗口中按序接收到了对应的帧后,接收方才将排好序的帧交给上层,窗口才可以滑动。假设窗口大小为x,可能一次上交1-x帧数据给上层,这样窗口就可以滑动1-x个位置,窗口中又空出1-x个位置以接收新的帧。窗口的大小大于2的n -1次方时,如果有帧出错,发送方重传时,会产生二义性。