zoukankan      html  css  js  c++  java
  • TCP有限状态机分析

     原文地址:http://blog.csdn.net/randyjiawenjie/article/details/6397477

    表示感谢

    TCP状态机

     

    这幅图是TCP的状态机,看了2个小时,分析总结如下:

    (1)CLOSED 状态时初始状态。

    (2)LISTEN:被动打开,服务器端的状态变为LISTEN(监听)。被动打开的概念:连接的一端的应用程序通知操作系统,希望建立一个传入的连接。这时候操作系统为连接的这一端建立一个连接。与之对应的是主动连接:应用程序通过主动打开请求来告诉操作系统建立一个连接。

    (3)SYNRECVD:服务器端收到SYN后,状态为SYN;发送SYN ACK;

     (4) SYN_SENTY:应用程序发送SYN后,状态为SYN_SENT;

    (5)ESTABLISHED:SYNRECVD收到ACK后,状态为ESTABLISHED; SYN_SENT在收到SYN ACK,发送ACK,状态为ESTABLISHED;

    (6)CLOSE_WAIT:服务器端在收到FIN后,发送ACK,状态为CLOSE_WAIT;如果此时服务器端还有数据需要发送,那么就发送,直到数据发送完毕;此时,服务器端发送FIN,状态变为LAST_ACK;

    (7)FIN_WAIT_1:应用程序端发送FIN,准备断开TCP连接;状态从ESTABLISHED——>FIN_WAIT_1;

    (8)FIN_WAIT_2:应用程序端只收到服务器端得ACK信号,并没有收到FIN信号;说明服务器端还有数据传输,那么此时为半连接;

    (9)TIME_WAIT:有两种方式进入该状态:1、FIN_WAIT_1进入:此时应用程序端口收到FIN+ACK(而不是像FIN_WAIT_2那样只收到ACK,说明数据已经发送完毕)并向服务器端口发送ACK;2、FIN_WAIT_2进入:此时应用程序端口收到了FIN,然后向服务器端发送ACK;TIME_WAIT是为了实现TCP全双工连接的可靠性关闭,用来重发可能丢失的ACK报文;需要持续2个MSL(最大报文生存时间):假设应用程序端口在进入TIME_WAIT后,2个MSL时间内并没有收到FIN,说明应用程序最后发出的ACK已经收到了;否则,会在2个MSL内在此收到ACK报文;

     

     2011.9.14补充:

    关闭的状态转换比较复杂:现在设通信双方是A,B,A是主动发起关闭方

    (1)      主动发起关闭方:

    A首先主动发起FIN报文,准备关闭TCP连接,然后进入FIN_WAIT1状态;然后,如果A收到了ACK报文,就进入FIN_WAIT2状态;而如果A收到的是ACK + FIN,A进入TIME_WAIT状态。

    进入FIN_WAIT2状态,说明B还有数据发给A。过了不久之后,B发送FIN给A,然后,A发送ACK,并进入TIME_WAIT状态。当2个MSL内,没有收到FIN信号,那么TIME_WAIT就自动转化为CLOESD。(为什么TIME_WAIT状态要进过2个MSL(Maximum Segment Lifetime.)才能进入CLOSED状态?假设网路是不可靠的,最后A发出的ACK信号丢失,那么B就没有收到ACK,此时B还需要重新发一个FIN给A,这个过程最多需要2MSL,所以如果过了2MSL,没有再次收到B的FIN,那么,说明之间A发出的ACK被B收到了,所以可以可靠地关闭连接。)

    (2)      被动接收方

    B在收到A的FIN报文后,知道A准备关闭TCP连接了(注意只是A单方面关闭,也就是说,A还可以收数据,但是不准备发数据了)。B将发送ACK给A,然后B进入CLOSED_WAIT状态。如果此时B也有数据发送给A,那么就一直发送好了,反正A不会发数据了。此时A处于FIN_WAIT2状态。当B的数据发送完毕之后,那么B发送FIN给A,B进入LAST_ACK状态。当收到A发过来的ACK信号后,A进入CLOSED状态。

    问题:

    1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢
    这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

    TCP的关闭连接的时候,状态很多,以刚才的例子分类:一个是主动发起方涉及的状态,一个被动发起方涉及的状态:

     

    主动发起方:

    FIN_WAIT1(发出FIN信号)

    FIN_WAIT2(收到ACK信号)

    TIME_WAIT(收到FIN信号)

    CLOSED(2个MSL后,没有再次收到FIN,进入)

     

    被动接收方:

    CLOSED_WAIT(收到FIN信号)

    LAST_ACK(发出FIN信号)

    CLOSED(收到ACK信号,如果没有,再次发出FIN信号)

    2.为什么能三次握手、四次挥手可靠地建立关闭连接?

    注意可靠。

    答:在建立连接的时候,首先需要发起方发出请求(即发出带有SYN的报文),接收方收到后必须给发起方一个回应(ACK+SYN)

    ,关键是这里还没有完毕。因为网络是不可靠地,(a)如果发起方没有收到应答方的ACK+SYN报文,显然,说明报文丢失,必须重发请求;(b)如果发起方收到ACK+SYN后,不再向接收方发出ACK信号(更正于2011.9.17)(也就是只有两次握手,此时开始传递报文),那么从发起方的角度来看,它认为自己发出的ACK+SYN报文丢失了,接收方没有收到,所以它会再次重发。(c)当发起方发出ACK信号后,如果没有收到接收方再次发来的ACK+SYN报文,那么说明接收方收到了自己发出的ACK报文,所以可以建立连接了。

    举个例子,如何保障可靠通信:

    现在A和B两支军队准备在10:00同时发起进攻,如何才能保证这两支军队同时呢?

    现在A发出电报,“要求在10:00同时发起进攻”;

    B收到后,显然必须向A回复“收到,可以”。

    A在收到“收到,可以”的消息后,直到B已经收到了自己发出的消息。注意,这里还没有完,如果你站在B的角度去思考:“我发出了‘收到,可以’的消息,必须要求A给我一个回应。如果我没有收到回应,那么就说明我的这个消息没有送到A那里去”,那么,我得再传一次“收到,可以”的消息跟A。所以,A必须再次发出“你的消息已经收到”的消息发送给B。此时,如果A没有再次收到B发来的“收到,可以”的消息,就可以认为自己的“你的消息已经收到”送给了B。而实际上,如果B收到A发来的“你的消息”我已经收到,说明,自己此前发出的消息已经被A收到。

    这样,就可以保证A,B可靠地收到消息,保证他们在10:00准时发起进攻。
  • 相关阅读:
    Visualizing Concurrency in Go · divan's blog
    Trac常用插件描述!
    分布式 OLTP 数据库
    【SDCC讲师专访】PingCAP联合创始人兼CEO刘奇:好的产品应开源,不闭门造车-CSDN.NET
    XiaoMi/themis: Themis provides cross-row/cross-table transaction on HBase based on google's percolator.
    TiDB首页、文档和下载
    TeamGantt vs JIRA 2016 Comparison | FinancesOnline
    HandlerInterceptor拦截实现对PathVariable变量的读取
    大叔来说说Markdown的使用
    springcloud~配置中心实例搭建
  • 原文地址:https://www.cnblogs.com/AI001/p/3996954.html
Copyright © 2011-2022 走看看