TCP状态切换流程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP状态切换流程相关的知识,希望对你有一定的参考价值。

enum {
/*

* Description of States:
*
* TCP_SYN_SENT sent a connection request, waiting for ack
*
* TCP_SYN_RECV received a connection request, sent ack,
* waiting for final ack in three-way handshake.
*
* TCP_ESTABLISHED connection established
*
* TCP_FIN_WAIT1 our side has shutdown, waiting to complete
* transmission of remaining buffered data
*
* TCP_FIN_WAIT2 all buffered data sent, waiting for remote
* to shutdown
*
* TCP_CLOSING both sides have shutdown but we still have
* data we have to finish sending

*
* TCP_TIME_WAIT timeout to catch resent junk before entering
* closed, can only be entered from FIN_WAIT2
* or CLOSING. Required because the other end
* may not have gotten our last ACK causing it
* to retransmit the data packet (which we ignore)
*
* TCP_CLOSE_WAIT remote side has shutdown and is waiting for
* us to finish writing our data and to shutdown
* (we have to close() to move on to LAST_ACK)
*
* TCP_LAST_ACK out side has shutdown after remote has
* shutdown. There may still be data in our
* buffer that we have to finish sending
*
* TCP_CLOSE socket is finished
*/


* 连接已建立
*/
TCP_ESTABLISHED = 1,
/*
* 已发送SYN包
*/
TCP_SYN_SENT,
/*
* 已接收到SYN包
*/
TCP_SYN_RECV,
/*
* 执行主动关闭,已发送FIN包
*/
TCP_FIN_WAIT1,
/*
* 执行主动关闭,发送的FIN包后收到对端的ACK包
*/
TCP_FIN_WAIT2,
/*
* 执行主动关闭,,接收到对端的FIN包,并发送ACK包
*/
TCP_TIME_WAIT,
/*
* 连接初始状态
*/
TCP_CLOSE,
/*
* 执行被动关闭,接收到对端的FIN包,并发送ACK包
*/
TCP_CLOSE_WAIT,
/*
* 执行被动关闭,接收到FIN包后,发送自己的FIN包
*/
TCP_LAST_ACK,
/*
* 监听状态
*/
TCP_LISTEN,
/*
* 两端同时关闭,在发送FIN包后接收到对端的FIN包
*/
TCP_CLOSING, /* Now a valid state */

TCP_MAX_STATES /* Leave at the end! */
};

 

一、主动端

1、TCP_CLOSE ---->TCP_SYN_SENT

141 int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
142 {
143         struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
144         struct inet_sock *inet = inet_sk(sk);
145         struct tcp_sock *tp = tcp_sk(sk);
146         __be16 orig_sport, orig_dport;
147         __be32 daddr, nexthop;
148         struct flowi4 *fl4;
149         struct rtable *rt;
150         int err;
151         struct ip_options_rcu *inet_opt;
152 
153         if (addr_len < sizeof(struct sockaddr_in))
154                 return -EINVAL;
155 
156         if (usin->sin_family != AF_INET)
157                 return -EAFNOSUPPORT;
158 
159         nexthop = daddr = usin->sin_addr.s_addr;
160         inet_opt = rcu_dereference_protected(inet->inet_opt,
161                                              sock_owned_by_user(sk));
162         if (inet_opt && inet_opt->opt.srr) {
163                 if (!daddr)
164                         return -EINVAL;
165                 nexthop = inet_opt->opt.faddr;
166         }
167 
168         orig_sport = inet->inet_sport;
169         orig_dport = usin->sin_port;
170         fl4 = &inet->cork.fl.u.ip4;
171         rt = ip_route_connect(fl4, nexthop, inet->inet_saddr,
172                               RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
173                               IPPROTO_TCP,
174                               orig_sport, orig_dport, sk);
175         if (IS_ERR(rt)) {
176                 err = PTR_ERR(rt);
177                 if (err == -ENETUNREACH)
178                         IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
179                 return err;
180         }
181 
182         if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
183                 ip_rt_put(rt);
184                 return -ENETUNREACH;
185         }
186 
187         if (!inet_opt || !inet_opt->opt.srr)
188                 daddr = fl4->daddr;
189 
190         if (!inet->inet_saddr)
191                 inet->inet_saddr = fl4->saddr;
192         sk_rcv_saddr_set(sk, inet->inet_saddr);
193 
194         if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) {
195                 /* Reset inherited state */
196                 tp->rx_opt.ts_recent       = 0;
197                 tp->rx_opt.ts_recent_stamp = 0;
198                 if (likely(!tp->repair))
199                         tp->write_seq      = 0;
200         }
201 
202         if (tcp_death_row.sysctl_tw_recycle &&
203             !tp->rx_opt.ts_recent_stamp && fl4->daddr == daddr)
204                 tcp_fetch_timewait_stamp(sk, &rt->dst);
205 
206         inet->inet_dport = usin->sin_port;
207         sk_daddr_set(sk, daddr);
208 
209         inet_csk(sk)->icsk_ext_hdr_len = 0;
210         if (inet_opt)
211                 inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
212 
213         tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT;
214 
215         /* Socket identity is still unknown (sport may be zero).
216          * However we set state to SYN-SENT and not releasing socket
217          * lock select source port, enter ourselves into the hash tables and
218          * complete initialization after this.
219          */
220     tcp_set_state(sk, TCP_SYN_SENT);
221         err = inet_hash_connect(&tcp_death_row, sk);
222         if (err)
223                 goto failure;
224 
225         inet_set_txhash(sk);
226 
227         rt = ip_route_newports(fl4, rt, orig_sport, orig_dport,
228                                inet->inet_sport, inet->inet_dport, sk);
229         if (IS_ERR(rt)) {
230                 err = PTR_ERR(rt);
231                 rt = NULL;
232                 goto failure;
233         }
234         /* OK, now commit destination to socket.  */
235         sk->sk_gso_type = SKB_GSO_TCPV4;
236         sk_setup_caps(sk, &rt->dst);
237 
238         if (!tp->write_seq && likely(!tp->repair))
239                 tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
240                                                            inet->inet_daddr,
241                                                            inet->inet_sport,
242                                                            usin->sin_port);
243 
244         inet->inet_id = tp->write_seq ^ jiffies;
245 
246         err = tcp_connect(sk);
247 
248         rt = NULL;
249         if (err)
250                 goto failure;
251 
252         return 0;
253 
254 failure:
255         /*
256          * This unhashes the socket and releases the local port,
257          * if necessary.
258          */
259         tcp_set_state(sk, TCP_CLOSE);
260         ip_rt_put(rt);
261         sk->sk_route_caps = 0;
262         inet->inet_dport = 0;
263         return err;
264 }
265 EXPORT_SYMBOL(tcp_v4_connect);

 

 

2、TCP_SYN_SEND---->TCP_ESTABLISHED

 

5434 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
5435                                          struct tcphdr *th, unsigned len)
5436 {
5437         u8 *hash_location;
5438         struct inet_connection_sock *icsk = inet_csk(sk);
5439         struct tcp_sock *tp = tcp_sk(sk);
5440         struct tcp_cookie_values *cvp = tp->cookie_values;
5441         int saved_clamp = tp->rx_opt.mss_clamp;
5442 
5443         tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0);
5444 
5445         if (th->ack) {
5446                 /* rfc793:
5447                  * "If the state is SYN-SENT then
5448                  *    first check the ACK bit
5449                  *      If the ACK bit is set
5450                  *        If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send
5451                  *        a reset (unless the RST bit is set, if so drop
5452                  *        the segment and return)"
5453                  *
5454                  *  We do not send data with SYN, so that RFC-correct
5455                  *  test reduces to:
5456                  */
5457                 if (TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
5458                         goto reset_and_undo;
5459 
5460                 if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
5461                     !between(tp->rx_opt.rcv_tsecr, tp->retrans_stamp,
5462                              tcp_time_stamp)) {
5463                         NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSACTIVEREJECTED);
5464                         goto reset_and_undo;
5465                 }
5466 
5467                 /* Now ACK is acceptable.
5468                  *
5469                  * "If the RST bit is set
5470                  *    If the ACK was acceptable then signal the user "error:
5471                  *    connection reset", drop the segment, enter CLOSED state,
5472                  *    delete TCB, and return."
5473                  */
5474 
5475                 if (th->rst) {
5476                         tcp_reset(sk);
5477                         goto discard;
5478                 }
5479 
5480                 /* rfc793:
5481                  *   "fifth, if neither of the SYN or RST bits is set then
5482                  *    drop the segment and return."
5483                  *
5484                  *    See note below!
5485                  *                                        --ANK(990513)
5486                  */
5487                 if (!th->syn)
5488                         goto discard_and_undo;
5489 
5490                 /* rfc793:
5491                  *   "If the SYN bit is on ...
5492                  *    are acceptable then ...
5493                  *    (our SYN has been ACKed), change the connection
5494                  *    state to ESTABLISHED..."
5495                  */
5496 
5497                 TCP_ECN_rcv_synack(tp, th);
5498 
5499                 tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
5500                 tcp_ack(sk, skb, FLAG_SLOWPATH);
5501 
5502                 /* Ok.. it‘s good. Set up sequence numbers and
5503                  * move to established.
5504                  */
5505                 tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
5506                 tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
5507 
5508                 /* RFC1323: The window in SYN & SYN/ACK segments is
5509                  * never scaled.
5510                  */
5511                 tp->snd_wnd = ntohs(th->window);
5512                 tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
5513 
5514                 if (!tp->rx_opt.wscale_ok) {
5515                         tp->rx_opt.snd_wscale = tp->rx_opt.rcv_wscale = 0;
5516                         tp->window_clamp = min(tp->window_clamp, 65535U);
5517                 }
5518 
5519                 if (tp->rx_opt.saw_tstamp) {
5520                         tp->rx_opt.tstamp_ok       = 1;
5521                         tp->tcp_header_len =
5522                                 sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
5523                         tp->advmss          -= TCPOLEN_TSTAMP_ALIGNED;
5524                         tcp_store_ts_recent(tp);
5525                 } else {
5526                         tp->tcp_header_len = sizeof(struct tcphdr);
5527                 }
5528 
5529                 if (tcp_is_sack(tp) && sysctl_tcp_fack)
5530                         tcp_enable_fack(tp);
5531 
5532                 tcp_mtup_init(sk);
5533                 tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
5534                 tcp_initialize_rcv_mss(sk);
5535 
5536                 /* Remember, tcp_poll() does not lock socket!
5537                  * Change state from SYN-SENT only after copied_seq
5538                  * is initialized. */
5539                 tp->copied_seq = tp->rcv_nxt;
5540 
5541                 if (cvp != NULL &&
5542                     cvp->cookie_pair_size > 0 &&
5543                     tp->rx_opt.cookie_plus > 0) {
5544                         int cookie_size = tp->rx_opt.cookie_plus
5545                                         - TCPOLEN_COOKIE_BASE;
5546                         int cookie_pair_size = cookie_size
5547                                              + cvp->cookie_desired;
5548 
5549                         /* A cookie extension option was sent and returned.
5550                          * Note that each incoming SYNACK replaces the
5551                          * Responder cookie.  The initial exchange is most
5552                          * fragile, as protection against spoofing relies
5553                          * entirely upon the sequence and timestamp (above).
5554                          * This replacement strategy allows the correct pair to
5555                          * pass through, while any others will be filtered via
5556                          * Responder verification later.
5557                          */
5558                         if (sizeof(cvp->cookie_pair) >= cookie_pair_size) {
5559                                 memcpy(&cvp->cookie_pair[cvp->cookie_desired],
5560                                        hash_location, cookie_size);
5561                                 cvp->cookie_pair_size = cookie_pair_size;
5562                         }
5563                 }
5564 
5565                 smp_mb();
5566           tcp_set_state(sk, TCP_ESTABLISHED);
5567 
5568                 security_inet_conn_established(sk, skb);
5569 
5570                 /* Make sure socket is routed, for correct metrics.  */
5571                 icsk->icsk_af_ops->rebuild_header(sk);
5572 
5573                 tcp_init_metrics(sk);
5574 
5575                 tcp_init_congestion_control(sk);
5576 
5577                 /* Prevent spurious tcp_cwnd_restart() on first data
5578                  * packet.
5579                  */
5580                 tp->lsndtime = tcp_time_stamp;
5581 
5582                 tcp_init_buffer_space(sk);
5583 
5584                 if (sock_flag(sk, SOCK_KEEPOPEN))
5585                         inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
5586 
5587                 if (!tp->rx_opt.snd_wscale)
5588                         __tcp_fast_path_on(tp, tp->snd_wnd);
5589                 else
5590                         tp->pred_flags = 0;
5591 
5592                 if (!sock_flag(sk, SOCK_DEAD)) {
5593                         sk->sk_state_change(sk);
5594                         sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);
5595                 }
5596 
5597                 if (sk->sk_write_pending ||
5598                     icsk->icsk_accept_queue.rskq_defer_accept ||
5599                     icsk->icsk_ack.pingpong) {
5600                         /* Save one ACK. Data will be ready after
5601                          * several ticks, if write_pending is set.
5602                          *
5603                          * It may be deleted, but with this feature tcpdumps
5604                          * look so _wonderfully_ clever, that I was not able
5605                          * to stand against the temptation 8)     --ANK
5606                          */
5607                         inet_csk_schedule_ack(sk);
5608                         icsk->icsk_ack.lrcvtime = tcp_time_stamp;
5609                         icsk->icsk_ack.ato       = TCP_ATO_MIN;
5610                         tcp_incr_quickack(sk);
5611                         tcp_enter_quickack_mode(sk);
5612                         inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
5613                                                   TCP_DELACK_MAX, TCP_RTO_MAX);
5614 
5615 discard:
5616                         __kfree_skb(skb);
5617                         return 0;
5618                 } else {
5619                         tcp_send_ack(sk);
5620                 }
5621                 return -1;
5622         }
5623 
5624         /* No ACK in the segment */
5625 
5626         if (th->rst) {
5627                 /* rfc793:
5628                  * "If the RST bit is set
5629                  *
5630                  *      Otherwise (no ACK) drop the segment and return."
5631                  */
5632 
5633                 goto discard_and_undo;
5634         }
5635 
5636         /* PAWS check. */
5637         if (tp->rx_opt.ts_recent_stamp && tp->rx_opt.saw_tstamp &&
5638             tcp_paws_reject(&tp->rx_opt, 0))
5639                 goto discard_and_undo;
5640 
5641         if (th->syn) {
5642                 /* We see SYN without ACK. It is attempt of
5643                  * simultaneous connect with crossed SYNs.
5644                  * Particularly, it can be connect to self.
5645                  */
5646                 tcp_set_state(sk, TCP_SYN_RECV);
5647 
5648                 if (tp->rx_opt.saw_tstamp) {
5649                         tp->rx_opt.tstamp_ok = 1;
5650                         tcp_store_ts_recent(tp);
5651                         tp->tcp_header_len =
5652                                 sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
5653                 } else {
5654                         tp->tcp_header_len = sizeof(struct tcphdr);
5655                 }
5656 
5657                 tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
5658                 tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
5659 
5660                 /* RFC1323: The window in SYN & SYN/ACK segments is
5661                  * never scaled.
5662                  */
5663                 tp->snd_wnd    = ntohs(th->window);
5664                 tp->snd_wl1    = TCP_SKB_CB(skb)->seq;
5665                 tp->max_window = tp->snd_wnd;
5666 
5667                 TCP_ECN_rcv_syn(tp, th);
5668 
5669                 tcp_mtup_init(sk);
5670                 tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
5671                 tcp_initialize_rcv_mss(sk);
5672 
5673                 tcp_send_synack(sk);
5674 #if 0
5675                 /* Note, we could accept data and URG from this segment.
5676                  * There are no obstacles to make this.
5677                  *
5678                  * However, if we ignore data in ACKless segments sometimes,
5679                  * we have no reasons to accept it sometimes.
5680                  * Also, seems the code doing it in step6 of tcp_rcv_state_process
5681                  * is not flawless. So, discard packet for sanity.
5682                  * Uncomment this return to process the data.
5683                  */
5684                 return -1;
5685 #else
5686                 goto discard;
5687 #endif
5688         }
5689         /* "fifth, if neither of the SYN or RST bits is set then
5690          * drop the segment and return."
5691          */
5692 
5693 discard_and_undo:
5694         tcp_clear_options(&tp->rx_opt);
5695         tp->rx_opt.mss_clamp = saved_clamp;
5696         goto discard;
5697 
5698 reset_and_undo:
5699         tcp_clear_options(&tp->rx_opt);
5700         tp->rx_opt.mss_clamp = saved_clamp;
5701         return 1;
5702 }

 

 

 

二、被动打开

1、TCP_CLOSE ----> TCP_LISTEN

794 int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
795 {
796         struct inet_sock *inet = inet_sk(sk);
797         struct inet_connection_sock *icsk = inet_csk(sk);
798         int rc = reqsk_queue_alloc(&icsk->icsk_accept_queue, nr_table_entries);
799 
800         if (rc != 0)
801                 return rc;
802 
803         sk->sk_max_ack_backlog = 0;
804         sk->sk_ack_backlog = 0;
805         inet_csk_delack_init(sk);
806 
807         /* There is race window here: we announce ourselves listening,
808          * but this transition is still not validated by get_port().
809          * It is OK, because this socket enters to hash table only
810          * after validation is complete.
811          */
812     sk->sk_state = TCP_LISTEN;
813         if (!sk->sk_prot->get_port(sk, inet->inet_num)) {
814                 inet->inet_sport = htons(inet->inet_num);
815 
816                 sk_dst_reset(sk);
817                 sk->sk_prot->hash(sk);
818 
819                 return 0;
820         }
821 
822         sk->sk_state = TCP_CLOSE;
823         __reqsk_queue_destroy(&icsk->icsk_accept_queue);
824         return -EADDRINUSE;
825 }

 

 

2、TCP_LISTEN ----> TCP_SYN_RCVE

5434 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
5435                                          struct tcphdr *th, unsigned len)
5436 {
5437         u8 *hash_location;
5438         struct inet_connection_sock *icsk = inet_csk(sk);
5439         struct tcp_sock *tp = tcp_sk(sk);
5440         struct tcp_cookie_values *cvp = tp->cookie_values;
5441         int saved_clamp = tp->rx_opt.mss_clamp;
5442 
5443         tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0);
5444 
5445         if (th->ack) {
5446                 /* rfc793:
5447                  * "If the state is SYN-SENT then
5448                  *    first check the ACK bit
5449                  *      If the ACK bit is set
5450                  *        If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send
5451                  *        a reset (unless the RST bit is set, if so drop
5452                  *        the segment and return)"
5453                  *
5454                  *  We do not send data with SYN, so that RFC-correct
5455                  *  test reduces to:
5456                  */
5457                 if (TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
5458                         goto reset_and_undo;
5459 
5460                 if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
5461                     !between(tp->rx_opt.rcv_tsecr, tp->retrans_stamp,
5462                              tcp_time_stamp)) {
5463                         NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSACTIVEREJECTED);
5464                         goto reset_and_undo;
5465                 }
5466 
5467                 /* Now ACK is acceptable.
5468                  *
5469                  * "If the RST bit is set
5470                  *    If the ACK was acceptable then signal the user "error:
5471                  *    connection reset", drop the segment, enter CLOSED state,
5472                  *    delete TCB, and return."
5473                  */
5474 
5475                 if (th->rst) {
5476                         tcp_reset(sk);
5477                         goto discard;
5478                 }
5479 
5480                 /* rfc793:
5481                  *   "fifth, if neither of the SYN or RST bits is set then
5482                  *    drop the segment and return."
5483                  *
5484                  *    See note below!
5485                  *                                        --ANK(990513)
5486                  */
5487                 if (!th->syn)
5488                         goto discard_and_undo;
5489 
5490                 /* rfc793:
5491                  *   "If the SYN bit is on ...
5492                  *    are acceptable then ...
5493                  *    (our SYN has been ACKed), change the connection
5494                  *    state to ESTABLISHED..."
5495                  */
5496 
5497                 TCP_ECN_rcv_synack(tp, th);
5498 
5499                 tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
5500                 tcp_ack(sk, skb, FLAG_SLOWPATH);
5501 
5502                 /* Ok.. it‘s good. Set up sequence numbers and
5503                  * move to established.
5504                  */
5505                 tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
5506                 tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
5507 
5508                 /* RFC1323: The window in SYN & SYN/ACK segments is
5509                  * never scaled.
5510                  */
5511                 tp->snd_wnd = ntohs(th->window);
5512                 tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
5513 
5514                 if (!tp->rx_opt.wscale_ok) {
5515                         tp->rx_opt.snd_wscale = tp->rx_opt.rcv_wscale = 0;
5516                         tp->window_clamp = min(tp->window_clamp, 65535U);
5517                 }
5518 
5519                 if (tp->rx_opt.saw_tstamp) {
5520                         tp->rx_opt.tstamp_ok       = 1;
5521                         tp->tcp_header_len =
5522                                 sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
5523                         tp->advmss          -= TCPOLEN_TSTAMP_ALIGNED;
5524                         tcp_store_ts_recent(tp);
5525                 } else {
5526                         tp->tcp_header_len = sizeof(struct tcphdr);
5527                 }
5528 
5529                 if (tcp_is_sack(tp) && sysctl_tcp_fack)
5530                         tcp_enable_fack(tp);
5531 
5532                 tcp_mtup_init(sk);
5533                 tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
5534                 tcp_initialize_rcv_mss(sk);
5535 
5536                 /* Remember, tcp_poll() does not lock socket!
5537                  * Change state from SYN-SENT only after copied_seq
5538                  * is initialized. */
5539                 tp->copied_seq = tp->rcv_nxt;
5540 
5541                 if (cvp != NULL &&
5542                     cvp->cookie_pair_size > 0 &&
5543                     tp->rx_opt.cookie_plus > 0) {
5544                         int cookie_size = tp->rx_opt.cookie_plus
5545                                         - TCPOLEN_COOKIE_BASE;
5546                         int cookie_pair_size = cookie_size
5547                                              + cvp->cookie_desired;
5548 
5549                         /* A cookie extension option was sent and returned.
5550                          * Note that each incoming SYNACK replaces the
5551                          * Responder cookie.  The initial exchange is most
5552                          * fragile, as protection against spoofing relies
5553                          * entirely upon the sequence and timestamp (above).
5554                          * This replacement strategy allows the correct pair to
5555                          * pass through, while any others will be filtered via
5556                          * Responder verification later.
5557                          */
5558                         if (sizeof(cvp->cookie_pair) >= cookie_pair_size) {
5559                                 memcpy(&cvp->cookie_pair[cvp->cookie_desired],
5560                                        hash_location, cookie_size);
5561                                 cvp->cookie_pair_size = cookie_pair_size;
5562                         }
5563                 }
5564 
5565                 smp_mb();
5566                 tcp_set_state(sk, TCP_ESTABLISHED);
5567 
5568           

以上是关于TCP状态切换流程的主要内容,如果未能解决你的问题,请参考以下文章

使用 BottomNavigationView 在它们之间切换时保留片段状态

TCP连接建立 之 同时打开

在导航抽屉片段中保存视图页面片段的状态

TCP 之 FIN_WAIT_2状态处理流程

在 Fragment 中保存状态 WebView

android如何跨片段分离/附加保留视图状态