9.6.1 Why
数据发送方收到接收方的通告窗口为0时,就不能再发送数据,一直等到对方发送窗口更新为止。但对端发送的窗口更新报文可能会丢失,如果发送方只是等待的话会导致数据传输会一直停滞,最后连接会被断开。这时坚持定时器闪亮登场!数据发送方可以设置坚持定时器定时发送1个探测报文,对端收到后会对这个报文发送ACK报文,这样发送方就能及时得知窗口更新事件了。一旦窗口非0则数据传输就可以恢复正常的数据传输。
9.6.2 When
设置坚持定时器的时机有两个:
(1)TCP使用__tcp_push_pending_frames发送数据时:
2032 void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
2033 int nonagle)
2034 {
2035 /* If we are closed, the bytes will have to remain here.
2036 * In time closedown will finish, we empty the write queue and
2037 * all will be happy.
2038 */
2039 if (unlikely(sk->sk_state == TCP_CLOSE))
2040 return;
2041
2042 if (tcp_write_xmit(sk, cur_mss, nonagle, 0,
2043 sk_gfp_atomic(sk, GFP_ATOMIC))) //判断为真意味着所有发送出去的数据都已经被确认且发送队列中还有数据未发送,即可能是因为窗口太小无法发送
2044 tcp_check_probe_timer(sk); //设置坚持定时器
2045 }
tcp_check_probe_timer函数:
973 static inline void tcp_check_probe_timer(struct sock *sk)
974 {
975 const struct tcp_sock *tp = tcp_sk(sk);
976 const struct inet_connection_sock *icsk = inet_csk(sk);
977
978 if (!tp->packets_out && !icsk->icsk_pending) //所有发送出去的数据都已经被确认且未设置坚持定时器、重传定时器、ER定时器和TLP定时器
979 inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
980 icsk->icsk_rto, TCP_RTO_MAX);
981 }
(2)
收到