本文是向大家介绍tcp的三次握手四次挥手的全过程,能够让我们更熟悉面向连接的传输层控制协议的原理,保证了数据传输的稳定性和可靠性。
如果我们把网络体系按照OSI模型划分,那么不论是从上往下还是从下往上数,处于最中间的都是传输层,简直就是夹心面包中间的精华,也就是说传输层是一个承上启下的作用,传输层主要就干一件事,建立端到端的连接。
什么是端到端?
比如我们的客户端到服务端就是端到端,在进一步了解握手和挥手之前,我们先来了解一下电影《中国机长》
飞机有自己实时的飞行地址,空管局管制中心有自己的固定地址,正如客户端和服务端都有各自的IP地址,飞机上如果有什么情况就可以直接和管制中心联系,管制中心会有特定的工作人员对这辆飞机进行答复,飞机和管制中心有各自的地址,第一机长和第二机长有各自的端口号,管制中心的工作人员有各自的端口号,这样就能进行特定的联系了,就如同套接字socket是握手之前的核心条件。
什么是三次握手?
现在飞机遇到了故障,机长和管制中心汇报故障,申请一下高度,这里其实就是三次握手了,因为飞机在飞行过程中需要调整高度或者返航等操作需要得到同意才能执行,如果在没有得到同意飞机直接调整高度那么就很容易发生撞机。在计算机的世界也是一样的道理,在使用TCP连接的时候需要进行三次握手。但是怎么样的握手才能判断出哪些请求或者哪些响应需要丢弃,这才是握手机制的核心。
TCP报文里有SYN,ACk和FIN等标识,如果设置1就是开启这些标识,设置0就是关闭这些标识,首先在客户端发送TCP报文的时候,会把SYN开启,SYN原意是同步的意思,客户端表示想和服务端进行数据的同步,三次握手以后,客户端就可以和服务端互相发送信息,毕竟TCP是全双工的,所以可以互发信息,只是把SYN开启是不够的,报文里面还有一个重要的字段Sequence序号。
为什么还需要序号呢?
因为应用程序可能会连续发送多个序号给服务器,保证通道的唯一性,假设初始序号为8633,当服务端收到SYN以后就需要作出响应了,这时候服务器会在TCP报文中把SYN和ACK开启,ACK表示确认的意思,合起来就是确认同步的意思,那么服务器也生成自己的序号,假设序号是303,光序号还不够,还需要确认号,这个确认号就根据对方的序号+1得到,这样客户端在收到号码后-1就知道是不是自己发送的TCP报文了,最后客户端还需要确认,因为不确认的话,服务器不知道自己发送出去的“确认同步”是否被接收,于是必须再发送一次TCP报文来使连接正式建立,这里客户端会把ACK开启,这里的序号就用对方的确认号生成,并且在对方的序号+1,也就是303+1,那么问题又来了,如果每一次发送的SYN,服务器都要记住其序号,并且新生成自己需要记住的序号,那服务器就需要非常多的资源,如果黑客借此不断发送SYN又不进行下一步,就会导致服务器崩溃,就是典型的DDos攻击,因此服务器干脆不保存自己的序号,而是根据服务器的IP地址和端口号等私有信息进行算法运算得到序号。
过程
1握:客户端发送 syn 包给服务器端,进入 SUNC_SENT 状态
2握:服务器端发送 syn+ack包,同时也发syn包,从listen到syn-rcvd状态
3握:客户端接收来着服务端的syn+ack包,向服务器端发送确认包ack包
握手之后的下个步骤是什么呢?
分手吗?
握手之后就建立了连接,这时候客户端就可以发送HTTP请求了。
然后服务端响应内容,假设现在内容都交流完毕了,现在各自就会发送关闭连接的要求了,这个过程就是我们说的四次挥手,注意客户端和服务端都能主动发起关闭。
什么是四次挥手?
假设这里客户端主动发起关闭要求,这时候客户端会在报文里开启FIN和ACK两个控制位,FIN就是结束的意思,这里就是确认结束会话,因为在发送HTTP请求和响应的时候,序号和确认后不断递增,这里就不用固定数字来表示序号和确认号来,其他的套路和前面的一样,等服务端发送完数据以后会再发送一个FIN+ACK来确认,此时序号和确认号不需要改变,因为没有一来一回,只是多了一个控制位FIN来确认结果,最后客户端得到结果发送ACK确认,此时自己的序号需要用对方的确认号,自己的确认号用对方的序号+1,其实中间的ACK和FIN+ACK两步就可以证明,为什么要四次挥手呢?因为还可能存在未发送完毕的数据。
过程
第一次挥手:客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态。
第二次挥手:服务端收到FIN后,发送一个ACK给客户端,服务端进入CLOSE_WAIT状态。
第三次挥手: Server发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态。
第四次挥手:客户端收到FIN后,客户端进入TIME_WAIT状态,发送ACK给服务端,服务端进入CLOSED状态,完成四次握手。
那为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。
但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。
只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。