为什么需要三次握手?两次不行?

PS:这个问的太多了,大家要先理解 =》背诵,防止突然忘了也能说个大概。这道题在问的时候,可深可浅,看面试官自己的掌握力度。

当面试官问你为什么需要有三次握手、三次握手的作用、讲讲三次三次握手的时候,我想很多人会这样回答:

首先很多人会先讲下握手的过程:

1、第一次握手:客户端给服务器发送一个 SYN 报文。

2、第二次握手:服务器收到 SYN 报文之后,会应答一个 SYN+ACK 报文。

3、第三次握手:客户端收到 SYN+ACK 报文之后,会回应一个 ACK 报文。

4、服务器收到 ACK 报文之后,三次握手建立完成。

作用是为了确认双方的接收与发送能力是否正常。

这里我顺便解释一下为啥只有三次握手才能确认双方的接受与发送能力是否正常,而两次却不可以
第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。

第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。

第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。

因此,需要三次握手才能确认双方的接收与发送能力是否正常。

这样回答其实也是可以的,但我觉得,这个过程的我们应该要描述的更详细一点,因为三次握手的过程中,双方是由很多状态的改变的,而这些状态,也是面试官可能会问的点。所以我觉得在回答三次握手的时候,我们应该要描述的详细一点,而且描述的详细一点意味着可以扯久一点。加分的描述我觉得应该是这样:

刚开始客户端处于 closed 的状态,服务端处于 listen 状态。然后

1、第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN(c)。此时客户端处于 SYN_Send 状态。

2、第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s),同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。

3、第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态。

4、服务器收到 ACK 报文之后,也处于 establised 状态,此时,双方以建立起了链接

image-20230312145515220

三次握手的作用

三次握手的作用也是有好多的,多记住几个,保证不亏。例如:

1、确认双方的接受能力、发送能力是否正常。

2、指定自己的初始化序列号,为后面的可靠传送做准备。

1、(ISN)是固定的吗

三次握手的一个重要功能是客户端和服务端交换ISN(Initial Sequence Number), 以便让对方知道接下来接收数据的时候如何按序列号组装数据。

如果ISN是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。

2、什么是半连接队列

服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。

这里在补充一点关于SYN-ACK 重传次数的问题: 服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超 过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s, 2s, 4s, 8s,

三次握手过程中可以携带数据吗

很多人可能会认为三次握手都不能携带数据,其实第三次握手的时候,是可以携带数据的。也就是说,第一次、第二次握手不可以携带数据,而第三次握手是可以携带数据的。

为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据,因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。也就是说,第一次握手可以放数据的话,其中一个简单的原因就是会让服务器更加容易受到攻击了。

而对于第三次的话,此时客户端已经处于 established 状态,也就是说,对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据页没啥毛病。

发表评论

后才能评论

评论(17)

  • 卢然小子 游客 2021-11-01 3:38 下午

    三次握手的目的是为了防止已经失效的连接请求报文段突然又传到服务器,因而产生错误。请注意,这你说的是连接请求,也就是客户端调用connect时发送的syn分节。比如客户端A要和服务器B进行连接,在第一次连接的时候发送了一个连接请求,但是由于网络原因出现了延迟,然后客户端a又发送了一个连接请求并且成功建立了连接。这时候第一次的连接请求报文又达到了服务器端。如果不进行三次确认的话。服务器就会认为这是一个新的连接请求。然后发送确认报文表示同意建立连接。如果不采用三次握手,那么只要B端发出确认报文。就会认为新的连接已经建立,但是a端并没有发出建立连接的请求,因此不会去向b端发送数据b端没有收到数据就会一直等待这样b端就会白白浪费很多资源。如果采用三次握手的话,就不会出现这种情况,b端收到一个过时失效的报文之后向a端发出确认此时a端并没有要求建立连接所以就不会向b端发确认这个时候b端也能够知道连接没有建立。

  • 游客 2021-10-02 9:14 下午

    棒棒

  • Matthew华 游客 2021-10-01 9:44 下午

    深入浅出

  • lmj 游客 2021-09-26 9:52 上午

    棒(๑•̀ㅂ•́)و✧

  • 0.0 2021-08-08 9:14 下午

    “同时会把客户端的 ISN + 1 作为 ACK 的值”这里错了吧,ACK是标志位,ack是确认号=ISN+1。还有SYN_REVD貌似应该是SYN_RCVD

  • 你也想起舞吗 游客 2021-08-08 9:05 下午

    nice

  • 何豪冉 游客 2021-08-04 10:12 上午

    之前都是理解的懵懵懂懂,这下算是比较清晰了,谢谢博主分享!

  • 11 2021-06-29 11:01 上午

    最后一句话好像错了吧,第三次握手的时候服务器应该是只知道客户端的发送能力正常,但不知道它的接受能力是否正常,所以此时客户端是能携带数据的。

  • fbweie 2021-06-19 8:05 下午

    establised – > established ?

  • inx 游客 2021-06-16 8:40 上午

    好!