TCP之三次握手和四次挥手

854 阅读10分钟

前言

TCP协议作为传输层中的重要协议,也是网络协议中的重要知识点,其中TCP的三次握手和四次挥手历来都是面试官钟爱的高频考题,下面是我对TCP三次握手和四次挥手的一些理解,如有错误还请指正。

TCP头部标识符

TCP三次握手和四次挥手其实就是TCP建立连接和释放连接的过程,讲解之前得先了解一下TCP的头部标识符,标识符用来控制连接状态,有六种标识符:

  • SYN(synchronous建立联机)

    • 创建一个连接
  • ACK(acknowledgement 确认)

    • 确认接收到的数据
  • FIN(finish结束)

    • 终结一个连接
  • PSH(push传送)

    • 传输数据到应用层
  • RST(reset重置)

    • 重置请求连接
  • URG(urgent紧急)

    • 将该数据置于最前

三次握手

三次握手的目的

三次握手最主要的目的就是为了确认客户端和服务端的收发功能是正常的

  • 那么需要确认的功能有四个
    • 客户端的发送功能
    • 客户端的接收功能
    • 服务端的发送功能
    • 服务端的接收功能

形象比喻

将小明当作客户端,小红当作服务器端,两人写信告白:
第一次握手:
小明告诉小红:我喜欢你。
第二次握手:
小红告诉小明:我知道了,我也喜欢你。
此时小红并不确定小明是否收到了告白信,直到
第三次握手:
小明回信:我也知道了,我们在一起吧。此时才真正建立连接。

三次握手具体内容

image.png

第一次握手

客户端第一次向服务端发送一条连接请求数据,SYN = 1,ACK = 0就是表示当前的报文段是一个请求报文,发送的具体数据第一个字节编号记为x,赋值seq,然后客户端状态从CLOSED(关闭)状态进入SYN-SENT(发送)状态

第二次握手

服务端收到请求后,返回客户端的SYN = 1,加上自己的确认号ACK=1,表示当前报文段是一个同意建立连接的应答报文,发送的具体数据第一个字节编号记为y,赋值seq,希望客户端下一次返回编号x + 1个字节为止的数据,记为ack = x + 1,然后服务端状态从CLOSED(关闭)状态进入到SYN-RECEIVED(收到)状态

此时客户端得出客户端发送接收能力正常,服务端发送接收能力也都正常,但是此时服务器并不能确认客户端的接收能力是否正常(服务端目前只知道客户端发送功能没问题,而不知道客户端接收功能怎么样,需要服务端和客户端都知道了双方的收发功能都没问题了才算连接已经建立了)

!!!注意: 服务端或客户端都知道了双方的收发功能都没问题了才能开始数据传递(所以第三次握手中客户端是可以向服务端发送数据了),此时客户端已经知道了自己的发送和接收功能都没问题,也知道服务端的发送和接收功能没有问题,所以在第三次握手中客户端是可以携带数据发向服务端的。

第三次握手

客户端收到服务端返回的请求确认后,客户端便从SYN-SENT(发送)状态 进入到ESTABLISHED(已建立)状态再次发送数据,然后原封不动返回ACK = 1,这里就不需要再发送 SYN=1了,为什么呢?因为此时并不是跟服务端进行连接请求,而是连接确认,所以只需要返回ACK = 1代表确认,同样的,发送的具体数据第一个字节编号记为seq = x + 1,希望服务端下次传输的数据第一个字节编号记为ack = y + 1,服务端接收到此次应答后也从SYN-RECEIVED(收到)状态进入到ESTABLISHED(已建立)状态

自我总结: 这里是我用通俗一点的话来讲一下自己的理解,第一次握手客户端向服务端发送连接请求,确认客户端发送功能是否正常,同时自己进入发送状态(SYN-SENT),第二次握手服务端接收到了连接请求报文,验证了客户端发送功能正常也知道了服务端的接收功能正常,然后向客户端发送应答,验证服务端发送请求功能是否正常,并告诉客户端它的发送功能没问题,我能收到,同时进入收到状态(SYN-RECEIVED),第三次握手客户端接收到了服务器发送的连接应答,知道了自己(客户端)的发送请求没问题,也验证了客户端的接收功能和服务端的发送功能没问题,自此客户端知道自己收发功能都正常,进入已连接状态(ESTABLISHED), 然后向服务端发送确认收到应答,告诉服务端它发的东西我收到了,你的发送功能问题,服务器接收到这次应答之后就知道了自己的发送和接收功能都没问题,就进入已连接状态(ESTABLISHED),然后大家就能愉快的数据传递了。

为什么TCP建立连接需要三次握手,明明两次就可以建立连接

如果是两次握手,假设客户端发送连接请求A,但是因为网络原因造成了超时,这时TCP会启动超时重传机制,重新发一个连接请求B,此时请求B顺利达到服务端,服务端应答完成建立了连接,然后数据传递完成后断开连接然后两端进入CLOSED(关闭)状态,假设这时请求A在两端关闭之后又抵达服务端,此时服务端接收到了连接请求A以为客户端又发送了连接请求,然后对请求A进行应答进入SYN-RECEIVED(收到)状态,其实这个时候客户端已经关闭了无法发送应答,造成服务端一直等待,导致资源浪费,而如果是三次握手的话,服务端进入SYN-RECEIVED(收到)状态,如果一段时间内没接收到数据,会根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便客户端重新发送ACK包。但此时客户端其实已经寄了,所以在重复指定次数之后,仍然未收到客户端的ACK应答,那么一段时间后,服务端自动关闭这个连接,从而避免了服务端一直等待导致的资源浪费。\

一句话的总结: 主要目的:防止服务端一直等待,浪费资源。

四次挥手

有三次握手建立连接,自然也会有释放连接,也就是业内常说的四次挥手。

形象比喻

恋爱之后,小明和小红煲电话粥。依旧将小明当作客户端,小红当作服务器端。小明跟小红说话
第一次挥手:
小明说:我说完了。
第二次挥手:
小红说:好的,我知道了,我还没说完。
小红继续吧啦吧啦,说完之后
第三次挥手:
小红告诉小明:我说完了。
第四次挥手:
小明收到后告诉小红:好的,我知道了。等了2MSL之后小明挂断了。
如果此时小红说完,等了2MSL,小明一直不出声,这个时候就会重新说一次:我说完了。直到收到小明最后的回复,才挂断电话。

四次挥手内容

image.png

第一次挥手

客户端向服务端发送连接请求,FIN=1表示当前报文段是一个释放连接的请求,并且客户端停止发送数据,进入FIN-WAIT-1(终止等待1)状态

第二次挥手

服务端接收到客户端连接释放请求后,ACK=1表示服务端接受到了这条请求,而且服务端还会告诉应用层要释放TCP连接,然后向客户端发送确认报文表示自己知道了,服务端进入CLOSE_WAIT(关闭等待)状态,此时服务端不再接受客户端发送的数据了,但是此时服务端依旧可以向客户端发送数据

第三次挥手

客户端收到确认请求报文后进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文,服务端将剩余数据发送给客户端,FIN=1、ACK=1表示同意释放连接的应答报文,完毕后会向客户端发送连接释放请求,自己进入LAST_ACK(最后确认)状态

第四次挥手

客户端接收到了释放请求后,向服务端发送应答确认,此时客户端进入TIME_WAIT(等待)状态,该状态必须经过2MSL(报文在网络中持续的最大时间),然后就会撤销相应的TCB,若该时间段内没有服务端的请求,才会进入到CLOSED(关闭)状态,服务端在2MSL内接受到应答确认后会进入CLOSED(关闭)状态,否则会重传,到这里TCP连接就断开了,四次挥手完成。

自我总结: 第一次握手客户端向服务端发送连接请求,确认客户端发送功能是否正常,同时自己进入发送状态(SYN-SENT),第二次握手服务端接收到了连接请求报文,验证了客户端发送功能正常也知道了服务端的接收功能正常,然后向客户端发送应答,验证服务端发送请求功能是否正常,并告诉客户端它的发送功能没问题,我能收到,同时进入收到状态(SYN-RECEIVED),第三次握手客户端接收到了服务器发送的连接应答,知道了自己(客户端)的发送请求没问题,也验证了客户端的接收功能和服务端的发送功能没问题,自此客户端知道自己收发功能都正常,进入已连接状态(ESTABLISHED), 然后向服务端发送确认收到应答,告诉服务端它发的东西我收到了,你的发送功能问题,服务器接收到这次应答之后就知道了自己的发送和接收功能都没问题,就进入已连接状态(ESTABLISHED),然后大家就能愉快的数据传递了。

为什么客户端要进入 TIME_WAIT状态,等待2MSL时间才进入CLOSED状态?

MSL指的是报文在网络中最大生存时间。在客户端发送对服务端的FIN确认包ACK后,这个ACK包有可能因为网络原因到达不了,服务器端如果接收不到ACK包就会重新发送FIN包。所以客户端发送ACK后需要留出2MSL时间(ACK到达服务器器+服务器发送FIN重传包,一来一回)等待确认服务器端缺失收到了ACK包。也就是说客户端如果等待2MSL时间也没收到服务器端重传的FIN包,则就可以确认服务器已经收到客户端发送的ACK包

总结

有一张TCP状态变迁图,很具有代表性,有助于大家理解三次握手和四次挥手的状态变化。如下图所示,粗的实线箭头表示正常的客户端状态变迁,粗的虚线箭头表示正常的服务器状态变迁。

image.png