前言
本文转发自“Java团长”,点击蓝色字体即可跳转。
注:原文中有几处错误,在本文中已经尽量更正,并且在关键地方加上了强调字体,如果屏幕前的您还发现什么错误,欢迎在评论区进行评论,同时依旧向原作者表示感谢!
三次握手
- 常见面试题:
1)为什么需要有三次握手?
2)三次握手的作用是什么? - 需要三次握手才能确认双方的接收与发送能力是否正常
为啥只有三次握手才能确认双方的接受与发送能力是否正常,而两次却不可以:
- 第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
- 第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
- 第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
-
三次握手的过程应该回答得更详细一点,因为 三次握手的过程中,双方是有很多状态的改变的,而这些状态,也是面试官可能会问的点。详细的描述如下所示:
刚开始客户端处于CLOSED的状态
,服务端处于LISTEN状态
。然后:
1)第一次握手:客户端给服务端发一个SYN报文
,并指明客户端的初始化序列号ISN(c)
。此时客户端处于SYN_SENT状态
。
2)第二次握手:服务器收到客户端的SYN报文
之后,会以自己的SYN报文作为应答,并且也是指定了自己的初始化序列号ISN(s)
,同时会把客户端的ISN+1作为ACK的值
,表示自己已经收到了客户端的SYN,此时服务器处于SYN_RCVD的状态
。
3)第三次握手:客户端收到SYN报文
之后,会发送一个ACK报文
,也是一样把服务器的ISN+1作为ACK的值
,表示已经收到了服务端的SYN报文,此时客户端处于ESTABLISHED状态
。
4)服务器收到ACK报文
之后,也处于ESTABLISHED状态
,此时,双方便建立起了链接。 -
三次握手的作用:
1)确认双方的接收能力、发送能力是否正常。
2)指定自己的初始化序列号,为后面的可靠传送做准备。
3)如果是https协议的话,三次握手这个过程还会进行数字证书的验证以及加密秘钥的生成等。 -
关于“三次握手”知识点的延伸面试题:
1)(ISN)是固定的吗?
三次握手的一个重要功能是客户端和服务端交换ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。
如果ISN是固定的,攻击者很容易猜出后续的确认号,因此ISN是动态生成的。
2)什么是半连接队列?
服务器第一次收到客户端的SYN之后,就会处于SYN_RCVD状态
,此时双方还没有完成建立起连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
3)三次握手过程中可以携带数据吗?
第一次、第二次握手不可以携带数据,而第三次握手是可以携带数据的。
为什么会这样呢?假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的SYN报文中放入大量的数据,因此攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂的重复发SYN报文的话,会让服务器花费很多时间、内存空间来接收这些报文。也就是说,第一次握手可以放数据的话,会让服务器更加容易受到攻击。
而对于第三次的话,此时客户端已经处于ESTABLISHED状态,也就是说,对于客户端来说,它已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据。
四次挥手
- 刚开始双方都处于
ESTABLISHED状态
,假如是客户端先发起关闭请求,则:
1)第一次挥手:客户端发送一个FIN报文
,报文中会指定一个序列号。此时客户端处于FIN_WAIT-1状态
。
2)第二次挥手:服务端收到FIN之后,会发送ACK报文
,且把客户端的序列号值+1作为ACK报文的序列号值
,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT状态
。
3)第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发送给客户端一个FIN报文,且指定一个序列号。此时服务端处于LAST_ACK的状态
。
4)第四次挥手:客户端收到FIN之后,同样发送一个ACK报文作为应答,且把服务端的序列号值+1作为自己ACK报文的序列号值
,此时客户端处于TIME_WAIT状态
。需要过一阵子以确保服务端收到自己的ACK报文之后才会进入CLOSED状态
。
5)服务端收到ACK报文之后,就处于关闭连接的CLOSED状态了。 - “TIME_WAIT”这个状态是面试的高频考点,就是要理解:为什么客户端发送ACK之后不直接关闭,而是要等一阵子才关闭。这其中的原因是:要确保服务器是否已经收到了客户端发送的ACK报文,如果没有收到的话,服务器会重新发FIN报文给客户端,客户端再次收到FIN报文之后,就知道之前的ACK报文丢失了,然后再次发送ACK报文。
- “TIME_WAIT”状态持续的时间至少是一个报文的来回时间。一般会设置一个计时,如果过了这个计时没有再次收到FIN报文,则代表对方成功收到ACK报文,此时客户端进入CLOSED状态。
补充
- SYN-ACK重传次数的问题:
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为1s,2s,4s,8s…- 三次握手四次挥手中各个状态所包含的含义:
1)LISTEN-监听来自远方TCP端口的连接请求
2)SYN-SENT-在发送连接请求后等待匹配的连接请求
3)SYN-RECEIVED-在收到和发送一个连接请求后等待对连接请求的确认
4)ESTABLISHED-代表一个打开的连接,数据可以传送给用户
5)FIN-WAIT-1-等待远程TCP的连接中断请求,或先前的连接中断请求的确认
6)FIN-WAIT-2-从远程TCP等待连接中断请求
7)CLOSE-WAIT-等待从本地用户发来的连接中断请求
8)CLOSING-等待远程TCP对连接中断的确认
9)LAST-ACK-等待原来发向远程TCP的连接中断请求的确认
10)TIME-WAIT-等待足够的时间以确保远程TCP接收到连接中断请求的确认
11)CLOSED-没有任何连接状态。