精华内容
下载资源
问答
  • TCP四次挥手过程

    2020-10-03 10:18:17
    TCP四次挥手过程 (1)第一次挥手 客户端向服务器端发送TCP报文请求释放连接,然后停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。其中: 标记位为FUN 序号为seq=u (2)第...

    TCP四次挥手过程

    (1)第一次挥手
    客户端向服务器端发送TCP报文请求释放连接,然后停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。其中:
    标记位为FIN=1
    序号为seq=a
    (2)第二次挥手
    服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,但是可能还有数据没有传完,因此先回一个ACK应答报文,然后服务器端开始准备释放服务器端到客户端方向上的连接,其中:
    标记位ACK=1
    序号为seq=b
    确认号ack=a+1
    (3)第三次挥手
    等服务端不再发送数据时,服务器端做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一个FIN报文表示同意现在关闭连接,其中:
    标记位为FIN=1,ACK=1
    序号位seq=c
    确认号ack=a+1
    (4)第四次挥手
    客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,进入TIME-WAIT阶段等待2MSL并向服务器端发送一段报文,其中:
    标记位为ACK=1
    序号为seq=a+1
    确认号为ack=c+1

    为什么要挥手需要四次呢?

    从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手多了一次。

    为什么客户端要等待2MSL?

    MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
    这里2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的(看下图的第四个阶段),如果服务器端在1MSL内没有收到客户端发出的ACK应答报文,就会再次向客户端发出FIN报文,一来一回正好2MSL,如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文,客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;如果客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。

    在这里插入图片描述

    展开全文
  • TCP四次挥手过程分析

    2020-09-19 16:38:26
    1、tcp四次挥手过程状态迁移如下所示: 1)、客户端通过close系统调用向服务端发起第一次挥手请求,此时客户端将自己状态置为TCP_FIN_WAIT1状态; 2)、服务端收到fin请求后,将状态置为TCP_CLOSE_WAIT,并设置...

    1、tcp四次挥手过程状态迁移如下所示:

    1)、客户端通过close系统调用向服务端发起第一次挥手请求,此时客户端将自己状态置为TCP_FIN_WAIT1状态;

    2)、服务端收到fin请求后,将状态置为TCP_CLOSE_WAIT,并设置延时ack,然后通知服务端应用程序;

    3)、服务端应用程序通过close系统调用向客户端发起fin请求,同时回复之前客户端fin的ack,此时服务端将状态置为TCP_LAST_ACK状态;

    4)、客户端收到fin+ack后,先将状态迁移至TCP_FIN_WAIT2,然后创建tw socket,销毁旧的socket,向服务端回复ack,进入TCP_TIME_WAIT状态,启动超时定时器,等待TIME_WAIT状态超时,回收tw socket资源;

    5)、服务端收到ack后,回收socket资源;

    应用程序                                                    应用程序
       |                                                                   |      close系统调用
       |close系统调用                                            |  
       |                                                                   |  
                                                                                              
    客户端                                                        服务端            
                                           fin                                               
                                       -------------->                                    
    TCP_FIN_WAIT1                       TCP_CLOSE_WAIT      
                                          ack                                                    
                                      <--------------                                          
    TCP_FIN_WAIT2                                                                   
                                                                                                   
                                            fin                                    (收到close)            
                                     <-------------- TCP_LAST_ACK <----------
                            
    TCP_TIME_WAIT                
                                           ack
                                     -------------->  tcp_done(回收socket资源)

            
    (2MSL超时,释放socke资)

    以上流程可以看出,发起连接断开的客户端,最后回收socket资源后,还会创建一个time wait socket,这个time wait socket复用之前的socket信息,等待定时器超时后才回收tw socket,而服务端在收到最后一个挥手ack后,直接就回收socket,并不要等待超时,那发起连接断开的一段为什么需要TIME_WAIT状态呢?

    1)、防止最后一个ack丢失,如果服务端发送完fin后,一直没收到ack,那服务端会重发,这时候如果客户端socket已经释放了,那就会导致消息无人处理,报错;

    2)、防止之前的tcp连接,网络链路上还有数据残留的时候就创建新的tcp连接;

    2、客户端发起close流程

    sys_close
        __close_fd
            fput
                task_work_add(往进程添加一些work工作任务,在进程返回用户空间时会检查标志,通过do_notify_resume->tracehook_notify_resume->task_work_run调用真正的处理函数____fput)

                    ____fput
                        file->f_op->release        
                            sock_close
                                inet_release
                                    tcp_close

    void tcp_close(struct sock *sk, long timeout)
    {
    	struct sk_buff *skb;
    	int data_was_unread = 0;
    	int state;
    
    	lock_sock(sk);
    	sk->sk_shutdown = SHUTDOWN_MASK;
    
    	//如果还处在LISTEN状态, 则将icsk_accept_queue半连接队列的request删除
    	if (sk->sk_state == TCP_LISTEN) {
    		tcp_set_state(sk, TCP_CLOSE);
    
    		/* Special case. */
    		inet_csk_listen_stop(sk);
    
    		goto adjudge_to_death;
    	}
    
    	/*  We need to flush the recv. buffs.  We do this only on the
    	*  descriptor close, not protocol-sourced closes, because the
    	*  reader process may not have drained the data yet!
    	*/
    	//清空接收队列缓存的skb
    	while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
    		u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq;
    
    		if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
    			len--;
    			data_was_unread += len;
    			__kfree_skb(skb);
    	}
    
    	sk_mem_reclaim(sk);
    
    	/* If socket has been already reset (e.g. in tcp_reset()) - kill it. */
    	if (sk->sk_state == TCP_CLOSE)
    		goto adjudge_to_death;
    
    	/* As outlined in RFC 2525, section 2.17, we send a RST here because
    	* data was lost. To witness the awful effects of the old behavior of
    	* always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
    	* GET in an FTP client, suspend the process, wait for the client to
    	* advertise a zero window, then kill -9 the FTP client, wheee...
    	* Note: timeout is always zero in such a case.
    	*/
    	if (unlikely(tcp_sk(sk)->repair)) {
    		sk->sk_prot->disconnect(sk, 0);
    	} else if (data_was_unread) {
    		//如果close的时候,接收队列还有消息未处理,发送rst消息
    		/* Unread data was tossed, zap the connection. */
    		NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
    		tcp_set_state(sk, TCP_CLOSE);
    		tcp_send_active_reset(sk, sk->sk_allocation);
    	} else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
    		/* Check zero linger _after_ checking for unread data. */
    		sk->sk_prot->disconnect(sk, 0);
    		NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA);
    	} else if (tcp_close_state(sk)) { //这里先完成一次状态迁移   TCP_ESTABLISHED--->TCP_FIN_WAIT1
    		/* We FIN if the application ate all the data before
    		 * zapping the connection.
    		 */
    
    		/* RED-PEN. Formally speaking, we have broken TCP state
    		 * machine. State transitions:
    		 *
    		 * TCP_ESTABLISHED -> TCP_FIN_WAIT1
    		 * TCP_SYN_RECV	-> TCP_FIN_WAIT1 (forget it, it's impossible)
    		 * TCP_CLOSE_WAIT -> TCP_LAST_ACK
    		 *
    		 * are legal only when FIN has been sent (i.e. in window),
    		 * rather than queued out of window. Purists blame.
    		 *
    		 * F.e. "RFC state" is ESTABLISHED,
    		 * if Linux state is FIN-WAIT-1, but FIN is still not sent.
    		 *
    		 * The visible declinations are that sometimes
    		 * we enter time-wait state, when it is not required really
    		 * (harmless), do not send active resets, when they are
    		 * required by specs (TCP_ESTABLISHED, TCP_CLOSE_WAIT, when
    		 * they look as CLOSING or LAST_ACK for Linux)
    		 * Probably, I missed some more holelets.
    		 * 						--ANK
    		 * XXX (TFO) - To start off we don't support SYN+ACK+FIN
    		 * in a single packet! (May consider it later but will
    		 * probably need API support or TCP_CORK SYN-ACK until
    		 * data is written and socket is closed.)
    		 */
    		tcp_send_fin(sk);
    	}
    	
    	...
    }

    3、服务端收到fin包,先将状态置为TCP_CLOSE_WAIT

    tcp_data_queue
        tcp_fin

    void tcp_fin(struct sock *sk)
    {
    	struct tcp_sock *tp = tcp_sk(sk);
    
    	inet_csk_schedule_ack(sk);
    
    	sk->sk_shutdown |= RCV_SHUTDOWN;
    	sock_set_flag(sk, SOCK_DONE);
    
    	switch (sk->sk_state) {
    	case TCP_SYN_RECV:
    	case TCP_ESTABLISHED:
    		/* Move to CLOSE_WAIT */
    		//状态从TCP_ESTABLISHED变为TCP_CLOSE_WAIT,并设置延时ack pingpong=1
    		tcp_set_state(sk, TCP_CLOSE_WAIT);
    		inet_csk(sk)->icsk_ack.pingpong = 1;
    		break;
    
    	case TCP_CLOSE_WAIT:
    	case TCP_CLOSING:
    		/* Received a retransmission of the FIN, do
    		 * nothing.
    		 */
    		break;
    	case TCP_LAST_ACK:
    		/* RFC793: Remain in the LAST-ACK state. */
    		break;
    
    	case TCP_FIN_WAIT1:
    		/* This case occurs when a simultaneous close
    		 * happens, we must ack the received FIN and
    		 * enter the CLOSING state.
    		 */
    		tcp_send_ack(sk);
    		tcp_set_state(sk, TCP_CLOSING);
    		break;
    	case TCP_FIN_WAIT2:
    		/* Received a FIN -- send ACK and enter TIME_WAIT. */
    		tcp_send_ack(sk);
    		tcp_time_wait(sk, TCP_TIME_WAIT, 0);
    		break;
    	default:
    		/* Only TCP_LISTEN and TCP_CLOSE are left, in these
    		 * cases we should never reach this piece of code.
    		 */
    		pr_err("%s: Impossible, sk->sk_state=%d\n",
    		       __func__, sk->sk_state);
    		break;
    	}
    
    	/* It _is_ possible, that we have something out-of-order _after_ FIN.
    	 * Probably, we should reset in this case. For now drop them.
    	 */
    	skb_rbtree_purge(&tp->out_of_order_queue);
    	if (tcp_is_sack(tp))
    		tcp_sack_reset(&tp->rx_opt);
    	sk_mem_reclaim(sk);
    
    	if (!sock_flag(sk, SOCK_DEAD)) {
    		//唤醒用户进程收包,用户进程唤醒后在tcp_recvmsg里会检测到fin包,最终应用程序会调用close发送finish包
    		sk->sk_state_change(sk);
    
    		/* Do not send POLL_HUP for half duplex close. */
    		if (sk->sk_shutdown == SHUTDOWN_MASK ||
    		    sk->sk_state == TCP_CLOSE)
    			sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP);
    		else
    			sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
    	}
    }

    4、服务端应用程序调用close,向客户端发送fin

    tcp_close
        tcp_close_state(这里将服务端状态从TCP_CLOSE_WAIT迁移成TCP_LAST_ACK)
            tcp_send_fin

    5、客户端接收到服务端的fin+ack

    tcp_v4_do_rcv
        tcp_rcv_state_process(这里将状态从TCP_FIN_WAIT1迁移成TCP_FIN_WAIT2)

    int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
    {
    	/* 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(sock_net(sk), LINUX_MIB_TCPABORTONDATA);
    				tcp_reset(sk);
    				return 1;
    			}
    		}
    		/* Fall through */
    	//注意上面的TCP_FIN_WAIT1、TCP_FIN_WAIT2并没有break,所以TCP_FIN_WAIT1、TCP_FIN_WAIT2状态下也会执行tcp_data_queue
    	case TCP_ESTABLISHED:
    		tcp_data_queue(sk, skb);
    		queued = 1;
    		break;
    	}
    
    	/* tcp_data could move socket to TIME-WAIT */
    	if (sk->sk_state != TCP_CLOSE) {
    		tcp_data_snd_check(sk);
    		tcp_ack_snd_check(sk);
    	}
    
    	if (!queued) {
    discard:
    		tcp_drop(sk, skb);
    	}
    	return 0;
    }

            tcp_data_queue
                tcp_fin
                    tcp_send_ack(向服务端回复最后一个ack)
                        tcp_time_wait(将状态从TCP_FIN_WAIT2迁移成TCP_TIME_WAIT,启动超时定时器,等待超时回收tcp)

    void tcp_time_wait(struct sock *sk, int state, int timeo)
    {
    	const struct inet_connection_sock *icsk = inet_csk(sk);
    	const struct tcp_sock *tp = tcp_sk(sk);
    	struct inet_timewait_sock *tw;
    	struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
    
    	//申请一个time wait socket,socket状态为TCP_TIME_WAIT,并将旧的sk信息赋给time wait socket
    	tw = inet_twsk_alloc(sk, tcp_death_row, state);
    
    	if (tw) {
    		struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
    		const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
    		struct inet_sock *inet = inet_sk(sk);
    
    		tw->tw_transparent	= inet->transparent;
    		tw->tw_rcv_wscale	= tp->rx_opt.rcv_wscale;
    		tcptw->tw_rcv_nxt	= tp->rcv_nxt;
    		tcptw->tw_snd_nxt	= tp->snd_nxt;
    		tcptw->tw_rcv_wnd	= tcp_receive_window(tp);
    		tcptw->tw_ts_recent	= tp->rx_opt.ts_recent;
    		tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp;
    		tcptw->tw_ts_offset	= tp->tsoffset;
    		tcptw->tw_last_oow_ack_time = 0;
    
    #if IS_ENABLED(CONFIG_IPV6)
    		if (tw->tw_family == PF_INET6) {
    			struct ipv6_pinfo *np = inet6_sk(sk);
    
    			tw->tw_v6_daddr = sk->sk_v6_daddr;
    			tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
    			tw->tw_tclass = np->tclass;
    			tw->tw_flowlabel = be32_to_cpu(np->flow_label & IPV6_FLOWLABEL_MASK);
    			tw->tw_ipv6only = sk->sk_ipv6only;
    		}
    #endif
    
    #ifdef CONFIG_TCP_MD5SIG
    		/*
    		 * The timewait bucket does not have the key DB from the
    		 * sock structure. We just make a quick copy of the
    		 * md5 key being used (if indeed we are using one)
    		 * so the timewait ack generating code has the key.
    		 */
    		do {
    			struct tcp_md5sig_key *key;
    			tcptw->tw_md5_key = NULL;
    			key = tp->af_specific->md5_lookup(sk, sk);
    			if (key) {
    				tcptw->tw_md5_key = kmemdup(key, sizeof(*key), GFP_ATOMIC);
    				if (tcptw->tw_md5_key && !tcp_alloc_md5sig_pool())
    					BUG();
    			}
    		} while (0);
    #endif
    
    		/* Get the TIME_WAIT timeout firing. */
    		if (timeo < rto)
    			timeo = rto;
    
    		tw->tw_timeout = TCP_TIMEWAIT_LEN;
    		if (state == TCP_TIME_WAIT)
    			timeo = TCP_TIMEWAIT_LEN;
    		//启动60s定时器
    		inet_twsk_schedule(tw, timeo);
    		/* Linkage updates. */
    		__inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
    		inet_twsk_put(tw);
    	} else {
    		/* Sorry, if we're out of memory, just CLOSE this
    		 * socket up.  We've got bigger problems than
    		 * non-graceful socket closings.
    		 */
    		NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW);
    	}
    
    	tcp_update_metrics(sk);
    	//旧的sk资源释放
    	tcp_done(sk);
    }
    

    最后进入time wait定时器超时处理函数tw_timer_handler,回收time wait socket

    static void tw_timer_handler(unsigned long data)
    {
    	struct inet_timewait_sock *tw = (struct inet_timewait_sock *)data;
    
    	if (tw->tw_kill)
    		__NET_INC_STATS(twsk_net(tw), LINUX_MIB_TIMEWAITKILLED);
    	else
    		__NET_INC_STATS(twsk_net(tw), LINUX_MIB_TIMEWAITED);
    	inet_twsk_kill(tw);
    }
    

    6、服务端收到ack,回收socket

    tcp_rcv_state_process
        tcp_done(TCP_LAST_ACK状态下直接释放socket)

    展开全文
  • TCP三次握手抓包分析 3.1 问题 1)使用eNSP搭建实验环境,在Server1搭建Web服务,在交换机E0/0/2口开启抓包,在Client1上访问Web服务 2)抓包查看TCP三次握手过程 ...4 案例4:TCP四次挥手抓包分析 4.1 问题 1)使用eN

    TCP三次握手抓包分析
    3.1 问题
    1)使用eNSP搭建实验环境,在Server1搭建Web服务,在交换机E0/0/2口开启抓包,在Client1上访问Web服务

    2)抓包查看TCP三次握手过程

    3.2 方案
    使用eNSP搭建实验环境,如图-9所示。
    在这里插入图片描述

    图-9

    3.3 步骤
    实现此案例需要按照如下步骤进行。

    1)第一次握手,如图-10所示。
    在这里插入图片描述

    图-10

    2)第二次握手,如图-11所示。

    在这里插入图片描述
    图-11

    3)第三次握手,如图-12所示。
    在这里插入图片描述

    图-12

    4 案例4:TCP四次挥手抓包分析
    4.1 问题
    1)使用eNSP搭建实验环境,在Server1搭建Web服务,在交换机E0/0/2口开启抓包,在Client1上访问Web服务

    2)抓包查看TCP四次挥手过程

    4.2 方案
    使用eNSP搭建实验环境,如图-13所示。

    在这里插入图片描述
    图-13

    4.3 步骤
    实现此案例需要按照如下步骤进行。

    1)第一次挥手,如图-14所示。

    在这里插入图片描述
    图-14

    2)第二次挥手,如图-15所示。

    在这里插入图片描述
    图-15

    3)第三次挥手,如图-16所示。

    在这里插入图片描述
    图-16

    4)第四次挥手,如图-17所示。

    在这里插入图片描述
    图-17

    展开全文
  • 根据前一篇介绍TCP三次握手内核代码分析,下面来大致分析一下,四次挥手过程。 首先上一张四次挥手图片: 由上图可以观察到是客户端先发起的close操作(服务器先发起close操作也是同样的流程)。 (1)谁先close套接...

    根据前一篇介绍TCP三次握手内核代码分析,下面来大致分析一下,四次挥手过程。

    首先上一张四次挥手图片:
    在这里插入图片描述由上图可以观察到是客户端先发起的close操作(服务器先发起close操作也是同样的流程)。
    (1)谁先close套接字,谁就先发一个fin=1的数据包到对端(同时会把自己socket状态改成TCP_FIN_WAIT1),对端收到数据包之后,会判断是否含有fin=1的标志,如果有的话,则把当前socket的状态改为TCP_CLOSE_WAIT(也就是上图中的server端CLOSE_WAIT)
    (2)server端由于是TCP_ESTABLISHED状态(ESTABLISHED),所以无论接收到对端socket发过来的任何数据都会回复一个相应的ACK(对应于上图中ACK=1,seq=v,ack=u+1),紧接着如果server端不再向这个socket发送数据的时候,他也会发送一个fin=1的包,并且此时会带上ACK=1,表示我是为了回复上一次你给我的FIN=1那个数据包(意思就是你给我fin=1代表你不想发数据给我了,我这边如果不想发数据给你的话,也会发送fin=1的数据包),同时把socket状态改为TCP_LAST_ACK
    (3)client收到fin=1数据包的ACK之后,知道了服务器已经知晓我不给他发送数据了,此时会关闭socket的发送功能,然后把socket的状态改成TCP_FIN_WAIT2,同时开启定时器(定时时间为2MSL,定时器的作用是等待时间内是否会接收到server端的FIN数据包,如果不再收到说明服务器收到了我后续的ACK数据包,ACK代表客户端也知道服务器不再发送数据给我了),然后在发送一个ACK告知服务器我已知晓FIN=1(即你也不发送数据给我了)
    (4)服务器收到客户端的ACK之后,就知道客户端已知晓我不再给客户端发送数据了,此时针对于这个客户端socket收发功能都已没有,所以会直接清除这个socket配置
    (5)客户端定时器时间之内没有再次接收到FIN则认为服务器已收到ACK,此时关闭socket连接



    上层应用close-----》socket_file_ops->release(也就是sock_close)-----》sock_release-----sock->ops->release(也就是socket创建时inet_stream_ops->release,inet_release)-------》sk->sk_prot->close(也就是tcp_prot->close,tcp_close)------》tcp_send_fin到这里发送fin=1的数据包,更改状态为TCP_FIN_WAIT1

    net/ipv4/tcp_input.c:之后,服务器接收函数tcp_rcv_state_process-----》tcp_data_queue-------》tcp_fin到这里服务器收到fin数据包,更改状态为TCP_CLOSE_WAIT,同时会发送FIN=1的数据包,调用tcp_send_fin,发送ACK,调用tcp_ack_snd_check

    net/ipv4/tcp_input.c:客户端收到服务器第一次ACK会把状态改成TCP_FIN_WAIT2,并同时开启定时器来接收FIN数据包tcp_time_wait(sk, TCP_FIN_WAIT2, tmo),然后发送ACK,tcp_send_ack(sk);

    服务器收到ACK,调用tcp_done,销毁socket
    客户端定时器超时,调用tcp_done,销毁socket

    展开全文
  • TCP握手 所谓三握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下...
  • 上次写了TCP的三次握手,这次总结一下TCP四次挥手过程,理清楚为什么握手是三次,挥手需要四次。 TCP是面向连接的,连接的建立过程被称为“三次握手”,天下没有不散的宴席,有了连接的建立,就会有连接的...
  • 在连接中,哪一段先发送...(1) TCP客户端发送一个FIN+seq,用来关闭客户到服务器的数据传送。自身进入FIN_WAIT1状态,等待服务器的确认信号。此时服务器端进入COLSE_WAIT状态。 (2) 服务器收到这个FIN,它发回一...
  • 客户端打算关闭连接,此时会发送一个TCP首部FIN标志位被置位1的报文,也即FIN报文,之后客户端进入FIN_WAIT_1 状态 服务端接收改报文后,就向客户端发送ACK应答报文,接着服务器进入CLOSE_WAIT 状态 客户端收到...
  • 2020-05-26:TCP四次挥手过程

    千次阅读 2020-06-11 10:12:07
    评论
  • 我的理解是这样的:客户端C和服务端S通信。客户端C为关闭发起端 第一个回合:C发送FIN包,...那么s的读通道和c的写通道关闭 第二个回合:S发送FIN包,因为S的写通道还没关闭。...
  • TCP三次和四次挥手过程1、TCP报文段首部2、TCP三次握手过程及常见问题2.1 TCP三次握手过程2.2 常见问题2、TCP四次挥手过程及问题2.1 TCP四次挥手过程2.2 常见问题 1、TCP报文段首部     &...
  • TCP四次挥手

    2021-01-16 14:55:22
    TCP 四次挥手过程 第一次挥手:Client 发送一个FIN,用来关闭Client到server的数据传送,Client进入FIN_WAIT_1状态 第二次挥手:Server收到FIN后,发送一个ACK到Client,确认序号为收到序号+1 第三次挥手:...
  • TCP三次握手四次挥手过程 原文链接
  • 这就造成了四次挥手。 如果是三次挥手会有什么问题? 等于说服务端将ACK和FIN的发送合并为一次挥手,这个时候长时间的延迟可能会导致客户端误以为FIN没有到达客户端,从而让客户端不断的重发FIN。 不断的进行数据包...
  • TCP四次挥手整个过程

    2021-04-01 16:45:05
    tcp报文图示: 序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这...
  • TCP四次挥手过程:  1、第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态;  2、第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN...
  • 以前经常听见TCP三次握手和TCP四次挥手,但是自己都没有具体的了解过它们的过程。这次终于了解一些了,所以就记录一下把。 一、TCP三次握手: 当两台主机要进行相互通信时。要确保双方通信的正常,所以要确认两台...
  • TCP四次挥手调优

    2020-07-12 00:32:15
    TCP 4次挥手过程
  • Note:本文内容参考自《计算机网络 自顶向下方法 原书第六版》前言:...TCP连接的关闭——TCP四次挥手过程举个例子说明这个过程:假设是客户端发起终止TCP连接的请求第一步:客户进程向服务器进程发送一个特殊的TC...
  • 1、TCP四次挥手过程图 1、第一次挥手 客户端进程调用close或shutdown函数发出连接释放报文,并且停止发送数据。该报文首部中,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),...
  • TCP三次握手和四次挥手的过程 TCP三次握手过程 C->SYN->S S->SYN/ACK->C C->ACK->...TCP四次挥手过程 C->FIN->S S->ACK->C S->FIN->C C->ACK->S 四次...
  • 1.TCP四次挥手过程 2.挥手连环发问 上篇文章对于"三次握手”做了说明。本节我们对不常听见的“四次挥手”为大家详尽, 直观,完整地绍“挥手”的过程。 所谓的四次挥手即tcp连接的释放(解除)。连接的释放必须是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,912
精华内容 1,564
关键字:

tcp四次挥手过程