面试必问!!彻底搞清楚 tcp 的三次握手四次挥手

首先先说明,关于三次握手和四次挥手,是对于TCP/IP协议的,而不是说HTTP协议的;
这里大家应该清楚,HTTP协议本身是应用层的,协议本身并不能约束传输层的操作方式。不过现有 HTTP 协议实现的确是依赖于 TCP/IP 上的。所以才有数据传输层的三次握手。
如果传输层并不是 TCP/IP ,那就不一定有三次握手什么的了。

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在每次数据传输前需要进行三次握手,是保障其面向连接和可靠的这两个特性的基本需要。

三次握手

作用:建立连接

为了便于理解,在解释三次握手之前,先说明tcp几个标志位的意思:

  • SYN(synchronous建立联机) :表示建立一个连接,携带SYN报文段的为同步报文段;

  • ACK(acknowledgement 确认) :表示确认是否有效,携带ACK报文段的也称确认报文段;

  • Sequence number(顺序号码):用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节在数据流中的序号;主要用来解决网络报乱序的问题;

  • Acknowledge number: 32位确认序列号包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1,(不过,只有当标志位中的ACK标志为1时该确认序列号的字 段才有效);
    下面是用Ack表示,和上面的ACK不一样的哈。

  • FIN(finish结束):表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志 位的TCP数据包后,连接将被断开;

  • PSH(push传送)

  • RST(reset重置)

  • URG(urgent紧急)

所谓三次握手(Three-Way Handshake),即建立TCP连接,是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:

在这里插入图片描述

第一次握手:

  • 建立连接:客户端发送连接请求报文段,将SYN位置为1,Sequence Number为j(随机生成的); 然后,客户端进入SYN_SEND状态,等待服务器的确认
    目前的状态是:客户端发送了 (SYN, seq=j)给服务端;

第二次握手:

  • 服务器收到SYN报文段
    ①服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为j+1(Sequence Number+1);
    ②同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;
    ③当然,确认位即ACK,为1即为确认进行连接;
    服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
    目前的状态是:服务端发送(SYN,Ack=j+1,seq=k,ACK=1)给客户端;

第三次握手:

  • 客户端收到服务器的SYN+ACK报文段
    ①将Acknowledgment Number设置为y+1;
    ②确认位即ACK,为1即为确认进行连接;
    此时向服务器发送ACK报文段, 客户端发送(Ack=y+1,ACK=1)给服务端;

这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

下面再说一下,再整个3次握手的过程中,tcp的6个标志位的变化情况:

第一次握手时:
客户端需要建立连接,所以及那个SYN同步报文段的标志位写1
在这里插入图片描述

第二次握手时:
服务端在收到请求连接的报文后,会回应确认位和同步位
在这里插入图片描述

第三次握手:
此时客户端会确认回应服务端确认连接,将确认位写1
在这里插入图片描述

至此,tcp的3次握手,算是告一段落,下面开始说明4次挥手了。


四次挥手

作用:释放资源

在说四次挥手之前,要先说明一下,由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,下图描述的即是如此:
在这里插入图片描述

现在我们先以客户端主动关闭连接为例说明4次挥手的过程。

第一次挥手

  • 客户端先发送一个FIN给服务端,用来关闭客户端到服务端的数据传送,服务端进入FIN_WAIT_1状态。
    当然这个时候的发的是(FIN+ACK)报文,具体发送的数据是:
    标志位:FIN=1,ACK=1,
    序号:确认序号ack=m, 发送序号seq=x

第二次挥手

  • 服务端收到客户端的FIN之后,会将收到数据的这个事情告知给客户端,发送的是ACK报文,Server进入CLOSE_WAIT状态,客户端进入FIN_WAIT_2状态;
    标志位:ACK=1
    序号:确认序号ack=x+1,发送序号seq=y

第三次挥手

  • 服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态。
    标志位:FIN=1, ACK=1
    序号:发送序号seq=u,确认序号ack=x+1

第四次挥手

  • 客户端收到FIN后,客户端t进入TIME_WAIT状态,接着发送一个Ack给服务端,确认序号为收到序号+1,服务端进入CLOSED状态,完成四次挥手。
    标志位:ACK=1
    序号:确认序号ack=u+1, 发送序号seq=x+1

疑难解答

问题一:
相对于tcp的3次握手,他的4次挥手能不能简化成3次呢,比如把第二次和第三次挥手合并成一次挥手,这样是否可行?

答案:
不可行?
原因:从之前咱们了解到的socket的收发过程中,可以知道,在客户端先调用.close()关闭数据的发送之后,服务端收到这个消息(客户端不会发送数据给我了)之后,第一件事是干嘛呢,当然是告诉客户端:好的,我知道你不发数据给我了(此处标记位数据1)。
如果如你想的那样,服务端现在立马调用.close(),关闭服务端数据发送(此处标记为数据2)并跟随刚才的数据一起发过去,显然是不符合实际的。客户端调用.close()之后,服务端这边的recv()会解阻塞,但是,解开阻塞并不代表服务端就可以立刻调用.close()(也有可以立即调用的情况哦), 说不定中间还有什么延时或者其他动作无法立刻完成close()操作。
当然,你想让数据1等待数据2的话,又是不存在的,因为tcp数据连接是面向连接并且可靠的,如果让客户端一直死等,是万万不可的?

总结:
为什么建立连接是3次握手,资源释放是4次挥手?

这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。

问题二:
关于上面几个状态的解释

答案:

  1. FIN_WAIT_1: FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报
    文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。 (主动方)

  2. FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK信息),稍后再关闭连接。 (主动方)

  3. CLOSE_WAIT:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN 报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关 闭连接。(被动方)

  4. LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。(被动方)

  5. TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。
    如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方)

  6. CLOSED: 表示连接中断。

下面可以通过图解的方式帮助理解一下:
在这里插入图片描述

问题三:

TIME_WAIT的时间为什么是2msl,以及为什么需要进行等待

答案:
在进行第四次挥手的时候,客户端会将ACK报文发送给服务端,由于tcp是建立在面向连接的基础上的–“有来有往”,正常情况下,服务端需要返回给客户端一个ACK数据包,告诉客户端,我已经收到你的ACK包了,但是,这样会需要一直一来一回;然后,咱们的四次挥手里面就有这样的机制,就是在被动关闭的一端(本文案例中指的是服务端),服务端在第四次挥手的时候,需要有一个超时时间等待,比如说4s,如果超出4s的超时时间,服务端没有接收到客户端发来的第四次挥手的数据,那么服务端会把第三次挥手的内容再次发送(服务端以为客户端没有收到它发的第三次挥手的内容,所以又发了一次,但是实际上客户端收到并且发送了第四次挥手的数据包),此时,我们的TIME_WAIT就发挥作用了,它是主动发起断开连接的一方的需要进行的等待实际时间,等待的作用就是,如果服务端没有收到第四次挥手的内容,那么服务端会再次发过来,那么,客户端就需要等着,看服务端会不会再次发送数据过来,如果超过这2sml时间服务端还没有发数据过来,那客户端就认为服务端已经接收到第四次挥手发送的数据了。

至于TIME_WAIT为何是2sml呢?
SML:Maximum Segment Life,表示TCP 对TCP Segment 生存时间的限制。可以理解为,数据包早网络上存活的最长时间,一来一回的话,就是2倍喽。


注意

  • RFC793明确规定,除了第一个握手报文SYN除外,其它所有报文必须将ACK = 1
  • 不要将确认序号Ack与标志位中的ACK搞混了。
  • 确认方Ack=发起方Req+1,两端配对。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在网络通信中,TCP协议是一种常用的可靠传输协议。而其中的三次握手四次挥手则是TCP连接的建立和断开过程中必然要遵循的步骤。因此,在面试中,面试官出现关于TCP三次握手四次挥手的问题也是很常见的。 面试官可能会问及TCP协议的基本原理,以及TCP连接建立、数据传输、连接关闭等方面的内容。针对TCP三次握手四次挥手面试官可能会问到以下问题: 1. TCP为什么要进行三次握手进行连接的建立? 三次握手是保证连接可靠性的一种手段。它主要是防止网络中存在延迟重复数据的情况,以及确保双方都可以正常收发数据。在进行三次握手时,客户端发送一个请求包,服务端接收并回应确认包,客户端再回应确认包,这样就完成了连接的建立。 2. TCP为什么要进行四次挥手关闭连接? 四次挥手是为了确保连接的正常关闭。在关闭连接时,双方需要先告知对方自己已经没有数据要传输,等待对方回应确认。在双方都没有数据要传输后,才会真正地关闭连接。四次挥手的过程中,主要是为了避免出现数据的丢失或错误。 3. 三次握手四次挥手的流程是什么? 三次握手:客户端向服务端发送SYN报文,服务端接收后发送SYN ACK报文,客户端接收后再发送ACK报文,完成连接的建立。 四次挥手:客户端发送FIN报文告知服务端自己已经没有数据要传输了,服务端回应ACK报文进行确认;服务端同样发送FIN报文告知客户端没有数据要传输,客户端返回ACK报文进行确认;之后等待一段时间,连接会自动关闭。 总的来说,要想在面试中应对TCP三次握手四次挥手的相关问题,需要实际理解这两个过程的原理和流程。同时,也需要知道在实际应用中,TCP协议是如何确保数据可靠性和连接可靠性的。最后,要明确无论是面试还是实际工作中,了解TCP协议和网络通信的相关知识都是非常重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值