美文网首页Java 杂谈
java实现TCPIP协议,令人懵逼的TCP三次握手过程:连接建

java实现TCPIP协议,令人懵逼的TCP三次握手过程:连接建

作者: 望月从良 | 来源:发表于2019-07-03 18:15 被阅读3次

    我想任何人只要对TCP协议有一丁点了解,都会知道它有一个三次握手过程。然而你未必知道这三次握手过程其实非常复杂,而且成本很高,很多上层协议就是为了避免三次握手带来的通讯延迟而放弃TCP协议的稳定性,转而依赖UDP,后者虽然数据传输没有保障,但是速度快,QQ通讯最早使用的就是UDP。

    TCP是一个比较”沉重“的协议,也就是为了保证数据传输万无一失,它必须要采取很多烦琐的保障措施。它在连接建立时会启动一个复杂的状态机来管理连接状态,协议会根据不同的情况,从当前所属状态进入另一个状态并采取相应的措施。

    TCP在连接,数据发送,断开连接的整个过程中可以简单的用三个状态来表示。第一个状态叫SYN,处于该状态时,通讯双方开始建立连接,同时双方协商好数据包的序列号。第二个状态叫FIN,此时所有数据发送完毕,其中一方像另一方发送断开连接的消息,然后自己进入连接断开状态。第三个状态叫ACK,它用来回复自己受到了对方发送过来的数据包。

    如果我们把上面简化的三种状态再度细化,那么整个通讯过程其实分为11种状态,我们分别看每种状态的描述:
    1, Closed。当双方处于没有联系的状况时,他们就处于关闭状态。根据通讯双方的角色,他们会通过不同的方式进入下一个状态。如果是服务器,它在开始通讯前会经过所谓的消极启动方式,也就是他会选择一个端口号,初始化一个socket结构,然然进入监听状态,此时它准备随时迎接客户端连接请求。如果是客户端,那么它会经过积极启动步骤,也就是主动向服务器发送一个SYN,也就是请求建立连接的消息。
    2,Listen。这个状态属于服务器才有,它时刻准备处理来自客户端的连接和数据发送请求,如果它收到客户端发来的SYN数据包,它会回复SYN+ACK数据包,然后进入SYN-RECEIVED状态,此时它准备与客户端发送或接受数据。

    这里需要提及什么叫SYN,或SYN+ACK数据包。在上一节我们曾用wireshark抓去过TCP数据包:


    屏幕快照 2019-06-24 下午4.22.26.png

    所谓SYN,ACK其实就是在Flag字段将某个比特位开启,这些比特位的作用我们在协议实现时会详细讲解。

    3,SYN-SEND。这个状态一般是客户端才有,它向服务器发送SYN数据包请求建立连接后就会进入该状态,它等待对方发送一个SYN数据包回来。如果服务器发回数据包中只有SYN状态没有ACK状态,那么它就会回发一个ACK数据包,然后进入SYN-RECEICED状态,然后等待对方也回发一个ACK数据包。如果服务器发来的包包含SYN和ACK状态,那么它直接进入ESTABLISHED状态,也就是说它进入连接建立完成的状态。

    4,SYN-RECEIVED,这个状态客户端才有,这种状况的出现是因为客户端发送SYN数据包请求建立连接,但是服务器端只回发一个SYN数据包,其中没有启动ACK比特位,这表示服务器知道客户端想建立连接,但服务器还没准备好,此时它只能等待,知道对方发送一个ACK包过来,然后进入ESTABLISHED状态。

    5,ESTABLISHED。进入这个状态表示三次握手已经完成,双方可以开始进行数据交换,这个状态知道数据发送完毕才或通讯出现异常后转让连接断开阶段。一种情况是本方想断开连接,于是本方向对方发送的FIN数据包,然后进入FIN-WAIT-1状态。一种情况是对方想断开连接,于是对方发来了FIN数据包,然后本方发送一个ACK数据包,接着进入CLOSE-WAIT状态。

    6,CLOSED_WAIT。通讯的一方接收到另一方关闭连接的通知数据包FIN,此时客户端的TCP协议层将对方要关闭连接的消息发送给当前进程,等待上层应用处理连接关闭事件,然后它向对方发送一个FIN数据包,并等待对方回发一个ACK数据包,同时进入到LAST-ACK状态。

    7,LAST-ACK。当前设备收到了对方发来的关闭连接通知包FIN,同时也回发了ACK,以及自己向对方也发送了FIN数据包,此时等待对方发过来ACK数据包以便确认对方收到了本方发出的FIN数据包。当收到对方发来的ACK包后,本方进入CLOSED状态,双方的连接成功断开。

    8,FIN-WAIT-1。当前设备发送给对方FIN包要求断开连接后,等待对方发回ACK数据包,或者是等待对方发出FIN数据包。如果本方发送FIN包,然后收到对方发来的ACK包,那么就进入FIN-WAIT-2状态,如果等到的不是ACK包而是对方发来的FIN包,那么就进入CLOSING状态。

    9, FIN-WAIT-2。本方发送FIN要求断开连接,然后收到了对方回发的ACK包后进进入该状态,此时它等待对方发送FIN包过来,当成功等到对方发来的FIN包后,它立马回发ACK包然后进入到TIME-WAIT状态。

    10,CLOSING。当前设备收到对方发来中断连接的FIN数据包后也回发了ACK确认数据包,然后自己也发送了FIN数据包,当还没等到对方发来的ACK确认数据包。如果成功等到了对方发来的ACK数据包后,它会进入到TIME-WAIT状态。

    11,TIME-WAIT。当前设备收到对方发来的FIN中断连接数据包,然后也回发了ACK数据包。接着它自己又向对方发送了FIN数据包,然后也收到了对方发来的ACK确认数据包。此时理论上连接已经成功断开,当设备需要等待一会,以便确定对方接收到自己发出的ACK包,等待一段时间后自动进入CLOSED状态。

    上面的状态转换过程请看下图:

    不知道你看到上面的状态转换图时,有没有被转来绕去的路径给搞懵逼,反正我是懵了,TCP协议为了保证数据传输的稳定性,不得不通过增加协议的复杂性来实现,上面状态描述只是简要描述,很多状态有很多细节依然需要处理,如果你对这些状态及其转换流程依然感觉到糊里糊涂,那不要紧,我们先有一个大概框架,在后面我们代码实现时,很多现在搞不清楚的东西会慢慢变得清晰起来。

    更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:


    这里写图片描述 新书上架,请诸位朋友多多支持: WechatIMG1.jpeg

    相关文章

      网友评论

        本文标题:java实现TCPIP协议,令人懵逼的TCP三次握手过程:连接建

        本文链接:https://www.haomeiwen.com/subject/rtvthctx.html