TCP在CLOSE_WAIT状态还能收到报文

TCP状态转换

我们都知道 TCP 是全双工通信,当客户端发送 FIN 后,服务端回复 ACK 进入 CLOSE_WAIT 状态,这个时候对于客户端来说,发送功能没有了,但是还可以正常接收服务端的数据,对于服务端来说,既可以接收客户端的数据也可以给客户端发数据。当被动关闭方在 CLOSE_WAIT 状态下接收到数据时,它依然会遵循 TCP 的协议规范,对接收的数据进行确认,即向对方发送 ACK 报文。这是 TCP 协议确保数据可靠传输的基本行为,确保每一个数据包都被确认接收。所以如果服务端在 CLOSE_WAIT 状态,客户端有报文过来,服务端是能正常接收并且回复 ACK 确认的,客户端也能收到这个 ACK。

总结来说,在 CLOSE_WAIT 状态下,不仅可以接收数据,而且对接收到的数据会正常回复 ACK 报文。不过,需要注意的是,处于这个状态应当尽快完成数据处理并主动关闭连接,避免资源被长时间占用。

上面是我们的理解,我们直接拿源码证明我们的理解:在 net/ipv4/tcp_input.c 文件里有个函数:

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                          struct tcphdr *th, unsigned len)
{
    // ...
    /* step 7: process the segment text */
    switch (sk->sk_state) {
    case TCP_CLOSE_WAIT:
    case TCP_CLOSING:
    case TCP_LAST_ACK:
        if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt))
            break;
    case TCP_FIN_WAIT1:
    case TCP_FIN_WAIT2:
        /* RFC 793 says to queue data in these states,
         * RFC 1122 says we MUST send a reset.
         * BSD 4.4 also does reset.
         */
        if (sk->sk_shutdown & RCV_SHUTDOWN) {
            if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq &&
                after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONDATA);
                tcp_reset(sk);
                return 1;
            }
        }
        /* Fall through */
    case TCP_ESTABLISHED:
        tcp_data_queue(sk, skb);
        queued = 1;
        break;
    }
    // ...
}

可以发现 TCP_CLOSE_WAIT 最终还是落入了和 TCP_ESTABLISHED 一样的处理流程:tcp_data_queue(sk, skb)。所以源码证明我们上面的理解没有问题。


   转载规则


《TCP在CLOSE_WAIT状态还能收到报文》 吴杭沉 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
Linux 进程与线程模型 Linux 进程与线程模型
UNIX 的传统倾向于把一个任务交给一个进程全权受理。但一个任务内部往往不止一个执行流——就像公司里所有人做同一件事,每个人只负责一部分,粒度减小后各事情可以同时进行,同时大家又共享着所有资源。于是就有了线程:线程就是共享资源的不同的执行流
2020-03-29
下一篇 
Linux 僵尸进程的产生与处理 Linux 僵尸进程的产生与处理
可能很少有人意识到,一个进程调用 exit 之后,它并非马上就消失,而是留下一个称为僵尸进程(Zombie)的数据结构。在 Linux 进程的几种状态中,僵尸进程非常特殊:它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅
2020-03-17
  目录