TCP发送端在发送一个满窗口长度(最大65535字节)的数据后必须等待对端的ACK更新窗口后才能继续发送数据。在广域网中传输数据时,由于往返时间较长,发送端等待的时间也会较长,这样会使得TCP数据交互的速度大大降低(长肥管道现象)。使用窗口扩大选项可以使得发送端得到更大的通告窗口,这样就可以在ACK到来前发送更多的数据,减少了等待的时间,提高了数据传输效率。
窗口扩大因子(shift.cnt)的大小是8bit,所以其值最大为255。使用窗口扩大选项后,真正的通告窗口大小 = TCP头中的窗口值*2**shift.cnt。但由于TCP判断数据是新是旧的方法是:数据的序列号是否位于sun.una到sun.una + 2**31的范围内,如果是,则为新,否则为旧。故通告窗口大小在最大值不能大于或等于2**31,即max_windows <= 2**30。所以shitr.cnt的最大值为30 - 16 = 14。
窗口扩大选项只能在SYN包和SYN|ACK包中携带,但SYN和SYN|ACK包中通告的窗口不使用窗口扩大因子进行扩展。
窗口扩大选项必须双方都开启才能生效。
计算SYN包的窗口大小时:
2752 void tcp_connect_init(struct sock *sk)
2753 {
2754 const struct dst_entry *dst = __sk_dst_get(sk);
2755 struct tcp_sock *tp = tcp_sk(sk);
2756 __u8 rcv_wscale;
...
2789 tcp_select_initial_window(tcp_full_space(sk),
2790 tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
2791 &tp->rcv_wnd,
2792 &tp->window_clamp,
2793 sysctl_tcp_window_scaling, //内核选项开启WScale功能
2794 &rcv_wscale,
2795 dst_metric(dst, RTAX_INITRWND));
2796
2797 tp->rx_opt.rcv_wscale = rcv_wscale;
...
构建SYN|ACK时&