7.4 FIN及其ACK的接收

本文深入探讨了TCP协议中FIN和ACK标志的接收过程。当Linux内核接收到FIN标志,它会调用tcp_data_queue函数来进行相应的处理,这涉及到连接状态的改变和数据缓冲的操作。了解这一机制对于优化TCP连接管理和网络通信至关重要。

        TCP在收到FIN时,会调用tcp_data_queue函数进行处理:

 4300 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
4301 {
4302     const struct tcphdr *th = tcp_hdr(skb);
4303     struct tcp_sock *tp = tcp_sk(sk);
4304     int eaten = -1;
4305     bool fragstolen = false;
...
4321     if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { //正序包
...
4344         if (eaten <= 0) { //没有在进程上下文中被提前copy进用户缓存
4345 queue_and_out:
4346             if (eaten < 0 &&
4347                 tcp_try_rmem_schedule(sk, skb, skb->truesize))
4348                 goto drop;
4349
4350             eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); //放入接收队列中
4351         }
4352         tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
4353         if (skb->len)
4354             tcp_event_data_recv(sk, skb);
4355         if (th->fin)
4356             tcp_fin(sk); //处理FIN包
4357
4358         if (!skb_queue_empty(&tp->out_of_order_queue)) {
4359             tcp_ofo_queue(sk);
...
        乱序包会在 tcp_ofo_queue函数整合时处理FIN标记:

 4023 static void tcp_ofo_queue(struct sock *sk)
4024 {
4025     struct tcp_sock *tp = tcp_sk(sk);
4026     __u32 dsack_high = tp->rcv_nxt;
4027     struct sk_buff *skb; 
...
4050         __skb_unlink(skb, &tp->out_of_order_queue);
4051         __skb_queue_tail(&sk->sk_receive_queue, skb);
4052         tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
4053         if (tcp_hdr(skb)->fin)
4054             tcp_fin(sk);
4055     }
4056 }
        看来FIN包的处理是由tcp_fin完成的:

3783 static void tcp_fin(struct sock *sk)
3784 {
3785     struct tcp_sock *tp = tcp_sk(sk);
3786
3787     inet_csk_schedule_ack(sk);
3788
3789     sk->sk_shutdown |= RCV_SHUTDOWN; //不允许再接受数据,因为对端不会再发送数据了
3790     sock_set_flag(sk, SOCK_DONE);  
3791
3792     switch (sk->sk_state) {
3793     case TCP_SYN_RECV:   
3794     case TCP_ESTABLISHED:    //未发送FIN就收到FIN
3795         /* Move to CLOSE_WAIT */       
3796         tcp_set_state(sk, TCP_CLOSE_WAIT);
3797         inet_csk(sk)->icsk_ack.pingpong = 1; //延迟回复ACK,期望发送数据或FIN时携带ACK确认
3798         break;
3799
3800     case TCP_CLOSE_WAIT:
3801     case TCP_CLOSING:    
3802         /* Received a retransmission of the FIN, do
3803          * nothing.      
3804          */
3805         break;
3806     case TCP_LAST_ACK:   //重传的FIN
3807         /*
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值