参考答案
TCP协议在传输数据的时候,客户端(Client)跟服务端(Server)会建立连接,然后把需要传输的文件进行分段,以及提供可靠传输和流量控制,在数据传输完成后,当前的会话也要断开连接,避免资源浪费。
TCP的三次握手,是建立连接的过程。四次挥手,是断开连接的过程。
一、TCP三次握手
先看图示,然后再来了解下,每一次握手都发生了什么。
图示中的字段含义:
- SYN:同步序列号,是用来建立连接的握手信号。
- ack:确认序号,当ACK为1时,ack有效,当ACK为0时,ack无效。
- seq:序号。
- ACK:确认序号有效。
- FIN: 结束标志,用来表示断开连接。
TCP协议还有一个特点:
就是面向字节流,它会把数据都分成一个个字节,然后进行分段传输,在分段传输的时候,每一段是由不同的字节序号组成的。最开始的时候,客户端和服务端都是Closed(关闭)状态,准备发送连接请求前,Server会进入LISTEN(监听)状态。
- 第一次握手: 客户端(Client)会给服务端(Server)发送请求报文段,并指定同步序列号SYN = 1,ACK = 0, 初始序号为seq = x,(seq里面就是字节的序号),同时TCP的客户端进程进入SYN-SENT(同步已发送)状态。
- 第二次握手: 服务端收到客户端发送的请求报文SYN后,会向客户端发送一个SYN报文作为应答,表示同意建立连接,同时指定了自己的SYN = 1, ACK = 1,还会向客户端发送seq = y,来表示自己的一个初始序号,同时也会告诉客户端下一次应该从哪开始发送的确认序号,由于客户端发送过来的初始序号seq = x, 所以确认序号ack = x + 1,这时,TCP的服务端进入SYN-RCVD(同步收到)状态。
- 第三次握手: 客户端收到服务端的确认报文之后,会再次向服务端发送确认信息,表示已经收到。所以ACK = 1, seq = x + 1, ack = y + 1。TCP建立连接,客户端和服务器进入ESTAB-LISTEND(已建立连接状态)状态。
二、为什么是三次握手
1. 通过上面的三次握手,可以很清楚的知道,每一步握手的目的是什么。
- 第一次握手:客户端发送建立连接的请求报文段,服务端收到了,这样服务端能够得出客户端的发送和自己的接收是没有问题的。
- 第二次握手:服务端也发送一个请求报文段,表示自己收到了来自客户端的建立连接请求报文段,同时客户端也收到服务器响应的这个报文段,这样客户端能够得出服务端的发送和自己的接收是没有问题的,但是服务端并不知道客户端的接收有没有问题(只是客户端自己知道)所以还需要第三次握手来告知服务端。
- 第三次握手:客户端接着发送请求报文段,表示自己收到了服务端的确认信息,然后服务端也正常收到了。自此,握手结束,可以知道双方的发送和接收是正常的。
2. 假如只握手了前两次,会造成什么样的后果呢?
客户端第一次向服务端发送了建立连接的请求报文段,有可能因为网络的原因滞留了,客户端就会认为这个请求失效了,会重新向服务端发送一个连接请求,然后服务器正常响应连接。
在某个时间段,第一次发送的连接请求才到达了服务端,如果没有第三次握手确认,那么此时服务端会误认为客户端又发了一个新的连接请求,会再一次响应客户端,客户端收到响应请求,发现这个请求刚刚已经发过了,而且也收到了服务端的响应,就忽略这个请求,但此时的服务端却还一直等待客户端的响应,这样就会造成资源的浪费。
3. 假如握手了四次,又会是什么样子呢?
第三次握手,服务端最后一次收到客户端的响应请求之后,如果此时进行第四次握手的话,那么应该是服务端接着去响应刚刚收到的这个请求,这个请求不管失败还是成功,意义都不大。因为三次握手之后,客户端和服务端都已经知道了双方的发送和接收是正常的,是可以进行数据传输的,就不需要再次发送确认请求了,而且完全可靠的通信协议也是不存在的。
三、TCP四次挥手
TCP断开连接,要经历四次挥手的过程。
- 第一次挥手: 客户端主动断开连接,向服务端发送FIN报文段,即连接释放报文段(FIN=1,序号seq=u),并且状态变为FIN-WAIT-1(终止等待1)。
- 第二次挥手: 服务端收到客户端的FIN报文段,响应请求,也向客户端发送一个ACK = 1,seq = y, ack = u + 1(三次握手阶段已经解释过seq和ack,没看懂的可以重新看一遍) 的报文段,来表示自己已经收到了客户端的断开连接的请求报文,同时将自己的状态变为CLOSE-WAIT(关闭等待)。
客户端收到第二次的挥手报文之后,也会将自身的状态变为FIN-WAIT-2(关闭等待),此时客户端已经断开了对服务端的连接,也就是说,客户端不能再向服务端发送数据了,但是服务端并没有断开连接,它仍然要向客户端发送未发送完的数据,即TCP处于半关闭状态,这也是为什么要四次挥手的原因。
- 第三次挥手: 等待一段时间,当服务端将剩余数据发送完后,也会向客户端发送一个FIN = 1 的报文段,其中seq = w, ack = u + 1, ACK = 1,同时,自身进入LAST-ACK(最后确认)状态,来等待客户端的ACK。
- 第四次挥手: 客户端收到服务端的断开释放报文段FIN,同样对它进行响应,向服务段发送ACK = 1 ,seq = u + 1, ack = w + 1的报文段,并且自身进入TIME-WAIT状态,一段时间过后,服务端收到客户端的响应报文,将自身状态变为Closed,客户端等待TIME-WAIT时间过后,也将变为Closed状态。四次挥手完毕,客户端和服务端断开连接。
四、为什么最后一次挥手,客户端还要进入一个TIME-WAIT状态?
如果客户端最后一次挥手发送的确认请求报文,服务端没有收到的话,服务端就会认为,是因为它自己发送的FIN报文段没有发送出去,导致客户端没有收到,客户端没有收到,就不会给它发送确认请求报文,于是,服务器会再次发送FIN报文段,所以有一个时长为2MSL的等待时间。
以上,是Java面试题【 TCP协议为什么是三次握手、四次挥手】的参考答案。
输出,是最好的学习方法。
欢迎在评论区留下你的问题、笔记或知识点补充~
—end—