握手4

时间:2019-03-25
本文章向大家介绍握手4,主要包括握手4使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

上一步分析到,服务器端将客户端发送的sk_buff,里面sock->sk_state 修改为 TCP_SYN_RECV,然后将该数据包发送给客户端。

接下来,我们进一步分析,客户端接收到来自服务器端的tcp报文后,会发生什么。

客户端处理该报文的顺序和服务器端处理该报文的顺序是一致的,为什么,因为他们都用的是TCP/IP 协议栈进行通信的。

我们看一下 针对状态为 TCP_SYN_RECV 的 sock 的处理。

case TCP_SYN_RECV:
        if (!acceptable)
            return 1;

        /* Once we leave TCP_SYN_RECV, we no longer need req
         * so release it.
         */
        if (req) {
            synack_stamp = tcp_rsk(req)->snt_synack;
            tp->total_retrans = req->num_retrans;
            reqsk_fastopen_remove(sk, req, false);
        } else {
            synack_stamp = tp->lsndtime;
            /* Make sure socket is routed, for correct metrics. */
            icsk->icsk_af_ops->rebuild_header(sk);
            tcp_init_congestion_control(sk);

            tcp_mtup_init(sk);
            tp->copied_seq = tp->rcv_nxt;
            tcp_init_buffer_space(sk);
        }
        smp_mb();
        tcp_set_state(sk, TCP_ESTABLISHED);
        sk->sk_state_change(sk);// 唤醒 sk 上的等待进程,实例为 sock_def_wakeup

        /* Note, that this wakeup is only for marginal crossed SYN case.
         * Passively open sockets are not waked up, because
         * sk->sk_sleep == NULL and sk->sk_socket == NULL.
         */
        if (sk->sk_socket)
            sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);

        tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
        tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale;
        tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
        tcp_synack_rtt_meas(sk, synack_stamp);

        if (tp->rx_opt.tstamp_ok)
            tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;

        if (req) {
            /* Re-arm the timer because data may have been sent out.
             * This is similar to the regular data transmission case
             * when new data has just been ack'ed.
             *
             * (TFO) - we could try to be more aggressive and
             * retransmitting any data sooner based on when they
             * are sent out.
             */
            tcp_rearm_rto(sk);
        } else
            tcp_init_metrics(sk);

        tcp_update_pacing_rate(sk);

        /* Prevent spurious tcp_cwnd_restart() on first data packet */
        tp->lsndtime = tcp_time_stamp;

        tcp_initialize_rcv_mss(sk);
        tcp_fast_path_on(tp);
        break;

客户端收到 服务器端的sock->sk_state 的状态为 TCP_SYN_RECV 时,会修改 sock 的状态为 TCP_ESTABLISHED。