在TCP/IP模型中的传输层,有一个协议,叫做TCP协议,TCP协议的特点是面向连接的,通信是双向的,也就是通信双方都可以进行收发数据,TCP协议可以保证数据收发的可靠性和有序性。
TCP的三次握手:
既然是面向连接,那么在双方通信之前,就要建立连接,TCP的连接是通过三次握手来进行的,图解如下:
第一次握手:client发起连接请求,向server发送SYN包,发送之后将自己的状态置为:SYN_SEND状态
第二次握手:server收到client的请求之后,立马进行响应,也就是向client发送SYN+ACK包,server发送的ACK包的序号等于发送方的SYN包的序号+1,发送完成之后,server进入SYN_RECV状态。
第三次握手:client收到server发送的响应之后,再向server发送一个确认包:ACK,此时ACK确认包的序号是上一次server发送的SYN包的序号+1,发送完成之后,client和server都进入ESTABLISHED状态。
这个时候连接就建立了,双方就可以进行通信,这就是TCP的三次握手。
为什么是三次握手,不是两次或者更多次?
现在我们假设A是客户端client,B是服务端server,既然是面向连接的协议,那么一次肯定是不行的,那么两次为什么不行呢? 现在假设现在A向B发送消息,但是由于网络延迟的原因,B没有收到消息,然后A就会重新发送SYN包,进行新的请求连接,此时B收到了第二次的连接请求,进行了响应,但是现在第一次的SYN在响应了第二次的请求之后也到了,此时服务器就会认为这是A新发起的请求,那么也会对这个SYN进行一次响应,但是此时A认为B对第一次的响应是无效的,就不会去处理,此时B就会一直为A的第一个SYN保留相关资源,就造成了资源的浪费。
而不是四次的原因就是,三次就可以保证连接的建立,四次以上就会把过程变得复杂和繁琐。
TCP的四次挥手
四次挥手的图解:
因为client和server都有可能发起关闭的请求,所以我们现在以client发起请求为例学习
第一次挥手:client发起关闭请求,向server发送FIN包,将自己的状态置为FIN_WAIT_1,意思就是:告诉server我没有数据向你发送了,我要关闭了。
第二次挥手:server收到client发送的FIN包之后,向client发送ACK包,然后将自己的状态置为CLOSE_WAIT,此时ACK包的序号和握手序号规则一样,是发起请求端的序号+1,意思就是:我知道你的数据发送完成了,但是我的数据还没有发送完成,所以我还不着急关闭连接,当client收到ACK确认之后将自己的状态置为:FIN_WAIT_2。
第三次挥手:当server的数据发送完成之后,server也要发起关闭的请求,向client发送FIN包,然后讲自己置为LAST_WAIT状态,告诉client,我的数据也发送完成了,现在我也要关闭连接了
第四次挥手:当client收到server发送的FIN包,然后将自己的状态置为TIME_WAIT,然后给server发送ACK确认包,此时的ACK确认包是server发送的FIN包的序号+1,意思就是告诉server。我知道你要结束了,现在断开吧。当serve收到client的确认之后,将自己的状态置为:CLOSED,最后一次client发送完ACK确认之后,等待2MSL,如果没有收到server的消息,那么就认为连接已经成功断开了,讲自己置为CLOSED状态。
Tip:MSL,任何报文在被丢弃前在网络中的最长时间,
为什么挥手是四次不是三次呢?
因为当client发送FIN之后,得到了确认,此时的client的状态是FIN_WAIT_2,此时client不能发送数据,但是可以接收数据。当client第一次发送FIN包的时候,server的数据不一定也发送完了,所以server暂时还不能关闭,此时就让client处于一个FIN_WAIT_2状态,让其继续接收server没有发送完成的数据。
为什么在client响应了server发送的FIN之后没有直接进入CLOSED状态呢?
因为在client响应了server发出的FIN请求之后,回应以ACK确认,如果此时client直接进入CLOSED状态,那么万一这个ACK包因为网络的原因没有即使的到达server,server就会再次的发送FIN包,请求关闭,但是此时client已经关闭了,那么server收到的就是RST,并会报告错误,此时就不复合TCP的可靠性原则。所以,综上所述,在client响应了server的FIN之后,状态只能是TIME_WAIT,等2MSL之后,client的状态才能置为CLOSED。
限于编者水平,文章难免有缺漏之处,欢迎指正。
如需转载,请注明出处。