您现在的位置是:首页 >技术教程 >TCP的三次握手和四次挥手网站首页技术教程

TCP的三次握手和四次挥手

打孔猿 2023-07-15 00:00:03
简介TCP的三次握手和四次挥手

三次握手

既然我们文章要说的是TCP的三次握手,和四次挥手,那么肯定是说的连接,也不是说的不其他的。那么它这个连接的过程说的是什么呢?

在这里插入图片描述

我们还是从图中理解,这样比较好理解,

  • TCP第一次握手:服务端的TCP进程先创建传输控制块TCB,准备接受客户端进程的连接请求,然后服务端进程处于LISTEN状态,等待客户端的连接请求,向服务端发出连接请求报文段,该报文段首部中的SYN=1,ACK=0,同时选择一个初始序号
    seq=i。TCP规定,SYN=1的报文段不能携带数据,但要消耗掉一个序号。这时,TCP客户进程进入SYN—SENT(同步已发送)状态。

简单的来说SYN—SENT状态,同步已发送状态,这是第一次握手的时候的状态。

  • TCP第二次握手:服务端收到客户端发来的请求报文后,如果同意建立连接,则向客户端发送确认。确认报文中的SYN=1,ACK=1,确认号ack=i+1,同时为自己
    选择一个初始序号seq=j。同样该报文段也是SYN=1的报文段,不能携带数据,但同样要消耗掉一个序号。这时,TCP服务端进入SYN—RCVD(同步收到)状态

这个第二次握手就会进入到同步收到状态。

  • TCP第三次握手:客户端进入ESTABLISHED(已建立连接)状态,TCP客户端进程收到服务端进程的确认后,还要向服务端给出确认。确认报文段的ACK=1,确认号ack=j+1,而自己的序号为seq=i+1。
    TCP的标准规定,ACK报文段可以携带数据,但如果不携带数据则不消耗序号,因此,如果不携带数据,则下一个报文段的序号仍为seq=i+1。

而当第三次握手连接完成的时候,已经标志了现在是已经完全的建立了连接,而这个时候就可以进行数据传递了。

有时候就有人会问了,为什么是三次握手而不是两次,也不是四五次呢?一般情况下问这种问题的都会是面试官,如果你在面试过程中已经把这个三次握手说完了之后,他有时候就会问这种问题,让你谈谈你自己的理解,那么为什么呢?

在RFC 793 指出的 TCP 连接使用三次握手的首要原因:he principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.

翻译过来就是三次握手的主要原因是防止旧的重复连接启动引起混淆。

也就是说,如果客户端连续发出多个SYN建立连接的报文的话,在网络拥堵的情况就会出现,一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端,那么此时服务端就会回一个 SYN + ACK 报文给客户端,客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。

而如果是两次握手,那么完蛋了,这时候判断不出这个连接是不是历史连接,中断还是不中断,这就没办法处理了,而三次握手就可以在客户端进行第三次发送报文的时候,有足够的上下文来判断这个连接到底是否属于历史连接。

那么为什么不是四次连接呢?大家可以继续翻到上面的图,如果是四次连接,那么也就是说,把ACK和SYN进行了分开,seq=y和ack=x+1这两步进行了分开,虽然四次握手也能够完成这一步,但是为了省事,人家还是三部就做完了,这样一来,也能确保双方的初始序列号能被可靠的同步,何必在多费一步操作呢?

四次挥手

既然我们TCP连接的时候进行了三次握手,为什么要中断的时候,我们要进行四次挥手呢?这还是得从图中来理解这个事情。

在这里插入图片描述

  • 客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送
  • 服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
  • 服务器B关闭与客户端A的连接,发送一个FIN给客户端A
  • 客户端A发回ACK报文确认,并将确认序号设置为收到序号加1

那么为什么是四次呢?之前阿粉面试别人的时候,有个哥们给我了一句话,由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这话比较笼统,但是没解释清楚为啥要做四次挥手,这是最尴尬的,然后问详细的样子是什么样的,他也解答的不错。

那么为什么呢?

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

也就是说,在关闭的时候,为了确认是否关闭连接,ACK的报文和FIN的报文是进行分开发送,而这时候,挥手的次数也就从三次变成了4次,这样是不是就好理解一点了。

参考链接:https://blog.csdn.net/yinlidong77/article/details/121013566

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。