握手4
Posted guoyu1024
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了握手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。
以上是关于握手4的主要内容,如果未能解决你的问题,请参考以下文章
Java Glassfish Spring Sockjs失败:WebSocket握手期间出错:意外的响应代码:500