面霸养成(三)TCP四次握手和三次挥手,为什么天天问还答不好呢?

三次握手

“我看你的简历上写了了解网络协议,那么你说说TCP的三次握手是怎样的吧。”

如果面试比较多的同学,对于上面这句话简直耳熟能详,关于三次握手的各种回答几乎都烂熟于心了,虽然三次握手比较简单,那么我们还是来稍微讲解一下。
首先上三次握手的经典图:
面霸养成(三)TCP四次握手和三次挥手,为什么天天问还答不好呢?_第1张图片
首先我们来看,其中有个SYN和一个ACK两种数据信息,还有一个seq和J、K两个数字,那么我们就从这几个方面来讲讲,三次握手究竟都干了些什么,怎么就能确定建立了一个TCP的链接呢。

TCP有六种标志位,发送数据的时不同的标志位代表不同的请求类型。共有6种分别是:SYN(synchronous建立联机) , ACK(acknowledgement 确认) ,PSH(push传送) ,FIN(finish结束), RST(reset重置) ,URG(urgent紧急)
Sequence number(顺序号码) ,Acknowledge number(确认号码)

首先,客户端(请求发起方)发送了一个SYN标志的包,意味着它想与服务端建立请求,如果服务端收到了这个TCP请求发现请求是SYN请求建立链接,那么服务端会返回给一个ACK应答包给客户端,同时自己也向客户端发送一个SYN的请求,当客户端收到了服务端的SYN之后,也会向服务端响应一个ACK请求,那么三次握手完成,请求建立成功。
三次握手的意义在于,不论是客户端还是服务端都具备了向对方发送SYN和ACK(即主动发送与被动响应)的能力,那么TCP的协议中就认为链接建立成功。

那么在上图中,seq又是做什么的呢?

熟悉TCP协议的同学应该知道,TCP是安全可靠且按续收发的协议,所以当TCP链接建立的生活,两端还需要约定请求包的起始序号,假设客户端从1开始,那么客户端之后的包的顺序就是1,2,3,4……,服务端就按照这个顺序来接收客户端发送的网络包,不会出现先处理了后发送的4号包,再处理3号包这种情况。同理,服务端也需要向客户端发送自己的起始序号,双方的包序号约定完成之后,才是真正的建立了安全的TCP链接。

四次挥手

相比于三次握手来讲,四次挥手的流程稍微复杂了一点,如果记得不清楚在面试中比较容易翻车,而且四次挥手还涉及到了一些隐秘复杂的问题,如果在生产环境中没有遇到或者对TCP的理解不是那么深刻,很容易被接下来的一些追问弄得手足无措。

同样,先上图:

面霸养成(三)TCP四次握手和三次挥手,为什么天天问还答不好呢?_第2张图片

在上图中,左边是发起断开连接的一方,右边是被动断开的一方(这很重要!)

可以看到,主动发起断开请求的一方,会先进入一个FIN1状态,同时发送一个FIN标志位的包给被动断开的一方,被动断开的一方收到后将自己的状态变为CLOSED-WAIT状态,并且响应一个ACK,同时自己也向主动断开方发送一个FIN标志位的请求,告诉他我也准备断开链接了,然后主动断开方收到FIN请求之后返回一个ACK表示我知道了我们可以断开了,然后两端断开,都进入CLOSED状态,整个TCP链接成功的关闭。

对照这张图,整个四次握手的流程还是十分清晰的, 如果你面试之前有所准备的话,说实话这两个关于TCP的问题你还是可以答得不错的,但是如果一个面试官想要考验你在实际生产中到底有没有遇到过并发下的TCP问题,那么肯定会深入追问一些问题。

你知道TIME-WAIT状态有什么意义吗,为什么等待2MSL的时间?

多数人到这就懵了,怎么四次握手都答出来了还要问一些这种东西。其实这个问题也很简单, 就是考察你对TCP协议的了解深度而已,不过是个概念性的东西。TIME-WAIT状态设计的意义就是为了确保能收到被动关闭一方发送给自己的最后的FIN和ACK的那个包,以及可能有一些其它之前延时还未收到的包等等,都是为了保证连接的正确关闭。
为什么要等待2MSL时间呢,MSL是一个报文在网络中生存的最大时间(假设一个报文的TTL是24,表示它最多只能存活24个路由器,一旦经过第25个路由器,那么它就死亡不会再往下传输了)。等待2MSL的意义就是,假设第一个报文发出来死在网络中了,那么TCP的超时重传机制会保证再发一次断开连接的信息,第二次可能就能正常收到了。不设置的更多时间的原因是,如果一个报文连续失败多次,可能是网络拥塞等异常情况, 那么就不需要等到确认信息就直接可以关闭连接,释放网络资源了。

假设你面试都答到这里了,那么起码你对TCP的四次挥手还是有一定的了解的,你可能松了一口气,但是马上又会听到追问:

你有关注过你的服务端出现过CLOSED-WAIT的状态吗,要是服务端有这个状态怎么办?

基本上问到这就已经过滤了大部分的面试者了,很多只背面试题的小伙伴们可能根本都不明白这个东西问的是什么意思,如果有研究或者有在生产上真的遇见这个问题的话,那么应该可以马上就回答出来。

那么什么时候服务端会出现CLOSED-WAIT呢?

按照四次挥手的图,来看只有被动关闭一方就会处在CLOSED-WAIT的状态。假设你们公司的客户端技术写了个bug,客户端在TCP链接的时候因为异常主动发起了断开链接的请求并且退出了程序。那么服务端就会被动的进入一个CLOSED-WAIT的状态,此时由于客户端的线程已经挂掉了,不会再给服务端来发送对应的FIN和ACK的包了,那么服务端的这一个链接就会一直在CLOSED-WAIT状态下等待。等于说这个链接被占用了却没有干任何的事情,那么在高并发短连接的系统里面,这是致命的!

服务端默认会等待两个小时,然后触发TCP的KeepAlived机制,会向客户端发送一个探活的包,此时客户端无法响应这个探活的包,那么服务端就知道客户端已经关闭连接了,它才会将连接状态变为CLOSED,这个链接才可以复用。

如果在生产环境下,许多个链接在CLOSED-WAIT状态下保持2个小时,那么对系统的并发性能影响是很大的,自然要考虑如何优化这个问题。作为服务端来讲,由于无法控制客户端是否会出异常,那么我们就需要保证我们的TCP探活时间不要有2个小时这么久,将它的时间改的稍微短一点,那么自然有利于解决这种问题。

在Linux中,修改内核的如下参数:

sysctl -w net.ipv4.tcp_keepalive_time=600   
sysctl -w net.ipv4.tcp_keepalive_probes=2
sysctl -w net.ipv4.tcp_keepalive_intvl=2

具体的值根据不同的业务和场景需求来分配即可。

总结

关于三次握手和四次挥手的就讲到这,具体想要更详细的了解TCP的机制,可以查阅一些书籍和网络资料,加深自己对网络协议的理解,面试的生活自然会给面试官耳目一新的感觉,马上就会觉得这小伙子不错!

你可能感兴趣的:(面霸养成计划)