本文转载自:Java进阶面霸
转载链接:https://www.toutiao.com/i6826256486050562571/
关于TCP的文章,网上有很多,讲“三次握手”和“四次挥手”的文章,头条里面也不止10篇。那些文章都很好的诠释了其原理,但是有些话语都干涩难懂,自己得反复的揣摩!
正好,霸哥今天在与朋友交流的时候,又看到有人在问TCP“三次握手”的问题:
其实,已经知道朋友肯定就能很快理解这句话的意思,但是还在摸索中的朋友呢?
下面霸哥将用自己的方式来讲讲,这TCP的“三次握手”和“四次挥手”到底是怎么一回事
在很久很久以前.....
面试官:说说什么是TCP?
程序员:传输协议
面试官:UDP也是,那为什么不用UDP呢?
程序员:因为UDP把数据传输过去就不管了,就假定接收方一定能接收到,可惜真实的网络环境不会如此单纯,甚至是复杂、残酷的。
在网络环境中无时无刻出现着丢包、阻塞、乱序的情况,一个不小心,数据可能就传输不到目的地了,这个时候就只能轮到TCP了
面试官:为什么TCP就可靠了呢?
程序员:就是因为它的“三次握手”和“四次挥手”哇!
面试官(邪魅一笑):那你来讲讲吧!
程序员:那您且细听分说
三次握手
程序员:这个“三次握手”就是通信建立链接的一个过程,看下图
通俗点讲就是:
客户端:你好,我是客户端
服务端:你好,客户端,我是服务端
客户端:你好,服务端
也经常把这个过程叫做“请求->响应->响应的响应”
面试官:打断一下,问个问题,为什么不是两次或者四次,非得是三次呢?
程序员:嗯,不错,是个称职的面试官!
试想一下,客户端发送一个连接,由于丢包、超时,或是服务端根本就不想建立连接,那这个时候客户端怎么办?
客户端并不能知道结果,就只有重复的发送连接请求,虽然这个时候服务端接收到了,但客户端仍不知道这事,只能继续发请求。
此时此刻,服务端接收了客户端的请求,当然知道了客户端的存在,如果服务端不同意建立连接,客户端重试几次后就会放弃,没问题。
如果服务端愿意建立连接呢?这个时候就会发送响应给客户端(好了,你别叫唤了,客户端我知道你了)
到了这一步,就已经进行了两次握手!理论上,这个时候已经可以进行连接了,但是问题来了:
因为对于服务端来说,这个响应的过程也可能会丢包,不一定会达到客户端,甚至客户端完全挂了都是可能的。
对于另外的情况,在第一次握手的时候,由于网络问题,客户端向服务端发送了多个建立连接的请求,假设其中某一个建立成功,做了简单的通信,然后结束了连接,本来很正常,但是另外一些请求由于网络的延迟又到了服务端,服务端会认为这是一个正常的请求,接下来又建立连接。
因此两次握手会有着种种问题。
为了保证服务端的响应能正确接收,客户端还是需要告诉给服务端,我收到了服务端的响应,也就是给服务端一个“响应的响应”,这样就是三次握手了。
面试官:要是这个“响应的响应”要是也出现了丢包等问题没有送到呢?
程序员:你存心找麻烦的吧?那照你这样说你就是手握烂了,也没办法保证消息100%可靠。三次握手,保证服务端、客户端双方都确认了对方存在就足够了。
四次挥手
面试官:嗯,不错,来说说“四次挥手”又是什么吧!
程序员:建立完连接后就可以传输数据了,传输完成后则需要四次挥手来告别,过程看下图
面试官:这你TMD没有上一张清晰啊!
程序员:哎呀~面试时间有限,将就着看看啦!
通俗来讲就是...
客户端:服务端啊,我要和你拜拜了
服务端:好的,我知道了
这个时候,客户端说了拜拜,也不会向服务端发送数据了,这个时候服务端是否能马上关闭呢?
不可以!因为服务端可能还没处理完相应的事情,所以还是要发送数据的,这个时候的状态为等待关闭的状态,当处理完后需要继续下面步骤。
服务端:客户端,我也要和你说拜拜了
客户端:拜拜,滚吧
程序员:其实在这里也会存在一些问题,当客户端说“拜拜”,服务端说“知道了”,这两次是没什么问题的。
但是当客户端说“拜拜”之后就直接夺门而出,这样就出问题了,因为服务端还没说“知道了”,就算已经说了“知道了”,客户端也可能已经走了。
这个时候为了解决这些问题,TCP协议还有几个状态来处理这些问题,就如上面看的状态图:
当客户端说“拜拜”,就进入 FIN_WAIT_1 的状态,服务端收到“拜拜”的消息后,发送“知道了”,然后就进入 CLOSE_WAIT 的状态。
当客户端接收到“知道了”,进入FIN_WAIT_2,过一段时间,客户端也接收到了“客户端,我也要和你说拜拜了”,客户端就应该发送“拜拜,滚吧”,说完这句话已经就可以走了。
但是客户端发送的消息没发送成功,服务端只能重复发送“我也要和你说拜拜”,可惜的客户端已经走了,永远不会给你响应。
由于存在这种问题,TCP协议要求客户端在离开之前先等待一会会,这个等待的时间叫TIME_WAIT,这个TIME_WAIT还有另外一个作用,如果客户端说完“拜拜”之后还需要等待一段时间,如果不等待就会直接释放端口。
在前面一次连接客户端说完“拜拜”就走了,服务端不知道,不停的回复“知道了”,这时候一个新的客户端连接了,这新客户端接收到了“知道了”这是不是就特别混乱了?
所以这TIME_WAIT就特别重要了,它可以保证让迟来的TCP报文段有足够的时间被识别和丢弃。连接结束了,网络中的延迟报文也应该被丢弃掉,以免影响立刻建立的新连接。
完
网友评论