• TCP中三次握手建立和四次握手释放以及相关问题


    本文基于个人所学和网上博文所整理,若有不妥处,欢迎留言指出

    TCP连接过程中标志位的意义:

    字符缩写 描述
    SYN 同步序号,表示此报文是一个连接请求或连接接受报文
    ACK 确认位,对接收到的报文的确认
    FIN 终止位,表示发送方完成数据发送,用来释放一个连接
    RST 复位连接,表示TCP连接中出现严重错误
    PSH 推送位,尽可能快递将数据送往接受进程

    一、三次握手建立

    1、三次握手建立连接详解

    TCP建立连接要进行“三次握手”,即交换三个分组。大致流程如下:

    (1)客户端向服务器发送一个SYN J,并进入SYN_SEND状态,等待服务器确认;;

    (2)服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1,此时服务器 进入SYN_RECV状态;

    (3)客户端再想服务器发一个确认ACK K+1,客户端和服务器进入 ESTABLISHED状态,完成三次握手。。

    三次握手发生在socket的那几个函数:

     从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

    总结:客户的的connect在第三次握手的第二次返回,二服务器的accept在三次握手的第三次返回。

    2、若是出现丢包的情况,会如何?(来自:TCP 为什么是三次握手,为什么不是两次或四次?车小胖的回答)(A对应客户端,B对应服务器)

    (1)第一个包,即A发给B的SYN 中途被丢,没有到达B

    A会周期性超时重传,直到收到B的确认;

    (2)第二个包,即B发给A的SYN +ACK 中途被丢,没有到达A

    B会周期性超时重传,直到收到A的确认;

    (3)第三个包,即A发给B的ACK中途丢失,没有到达B

    A发完ACK,单方面认为TCP为Established状态,而B显然认为TCP为Active状态:

    • 假定此时双方都没有数据发送,B会周期性超时重传,直到收到A的确认,收到之后B的TCP 连接也为 Established状态,双向可以发包。
    • 假定此时A有数据发送,B收到A的 Data + ACK,自然会切换为established 状态,并接受A的 Data。
    • 假定B有数据发送,数据发送不了,会一直周期性超时重传SYN + ACK,直到收到A的确认才可以发送数据。

    3、TCP 为什么是三次握手,为什么不是两次或四次?

    三次握手的目的是什么?以下引用知乎作者郭无心的回答:

    在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

    另外,三次握手的最主要目的是保证连接是双工的,可靠更多的是通过重传机制来保证的。我们可以通过打招呼的例子来说明。

    二、四次挥手释放

    1、四次挥手释放过程详解

    由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。 
    (1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。 
    (2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。 
    (3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。 
    (4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。 

    这里引用whuslei的博文TCP协议中的三次握手和四次挥手(图解)中更为生动的解释:

    假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭连接了"。Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,"就知道可以断开连接了"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!

     2、为什么连接的时候是三次握手,关闭的时候却是四次挥手?
    答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

    3、为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

    答:主要是防止最后一个ACK丢失!!!虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。另外在等待2MLS的时间中,五元组(源、目IP和端口号以及协议号)都不能用,是为了防止网络中迟来数据。 

     Ref:

    http://www.cnblogs.com/huhuuu/p/3572485.html

    http://blog.csdn.net/whuslei/article/details/6667471

    http://www.cr173.com/exam/Cisco_17954_1.html 

    http://www.8btc.com/baizhantingjiangjun(将军问题)

  • 相关阅读:
    sinaapp+wordpress
    用JavaScript实现本地缓存
    Javascript的IE和Firefox(火狐)兼容性
    150个javascript特效
    学习Javascript闭包(Closure)
    JS bingo卡片
    Response.Write详细介绍[转]
    JS实现鼠标经过时背景色缓慢改变
    为什么引用不了App_Code里的类
    SQL SERVER 2008 R2配置管理器出现“远程过程调用失败”【0x800706be】的解决办法
  • 原文地址:https://www.cnblogs.com/love-yh/p/7425031.html
Copyright © 2020-2023  润新知