zoukankan      html  css  js  c++  java
  • Linux网络编程——浅谈 TCP 三次握手和四次挥手

    一、tcp协议格式





    二、三次握手


    在 TCP/IP 协议中。TCP 协议提供可靠的连接服务,採用三次握手建立一个连接。

     


    第一次握手:建立连接时,client发送 syn 包(tcp协议中syn位置1。序号为J)到server,并进入 SYN_SEND 状态。等待server确认; 


    第二次握手:server收到 syn 包,必须确认客户的 SYN,同一时候自己也发送一个 SYN 包,即 SYN+ACK包(tcp协议中syn位置1,ack位置1。序号K,确定序号为J+1),此时server进入 SYN_RECV 状态。 


    第三次握手:client收到server的 SYN+ACK 包,向server发送确认包 ACK(tcp协议中ack位置1。确认序号K+1)。此包发送完毕,client和server进入 ESTABLISHED 状态,完毕三次握手。


     


    通过这种三次握手。client与服务端建立起可靠的双工的连接,開始传送数据。 三次握手的最主要目的是保证连接是双工的,可靠很多其它的是通过重传机制来保证的。可是为什么一定要进行三次握手来保证连接是双工的呢。一次不行么?两次不行么?


    我们举一个现实生活中两个人进行语言沟通的样例来模拟三次握手


    第一次对话: 

    老婆让甲出去打酱油。半路碰到一个朋友乙。甲问了一句:哥们你吃饭了么? 


    结果乙带着耳机听歌呢。根本没听到,没反应。

    甲心里想:跟你说话也没个音,不跟你说了,沟通失败。说明乙接受不到甲传过来的信息的情况下沟通肯定是失败的。

     

    假设乙听到了甲说的话,那么第一次对话成功,接下来进行第二次对话。 



    第二次对话: 

    乙听到了甲说的话,可是他是老外,中文不好。不知道甲说的啥意思也不知道如何回答。于是随便回答了一句学过的中文 :我去厕所了。甲一听立马笑喷了,“去厕所吃饭”?道不同不相为谋,离你远点吧。沟通失败。说明乙无法做出正确应答的情况下沟通失败。 


    假设乙听到了甲的话,做出了正确的应答,而且还进行了反问:我吃饭了,你呢?那么第二次握手成功。 


    通过前两次对话证明了乙可以听懂甲说的话,而且能做出正确的应答。

    接下来进行第三次对话。

     



    第三次对话: 

    甲刚和乙打了个招呼,突然老婆喊他。“你个死鬼,打个酱油咋这么半天,看我回家咋收拾你”,甲是个妻管严,听完吓得二话不说就跑回家了,把乙自己晾那了。

    乙心想:这什么人啊,得,我也回家吧,沟通失败。说明甲无法做出应答的情况下沟通失败。

     


    假设甲也做出了正确的应答:我也吃了。那么第三次对话成功,两人已经建立起了顺畅的沟通渠道,接下来開始持续的聊天。

     


    通过第二次和第三次的对话证明了甲可以听懂乙说的话。而且能做出正确的应答。 可见。两个人进行有效的语言沟通。这三次对话的过程是必须的。

     

    同理对于TCP为什么须要进行三次握手我们能够一样的理解: 

    为了保证服务端能收接受到client的信息并能做出正确的应答而进行前两次(第一次和第二次)握手,为了保证client可以接收到服务端的信息并能做出正确的应答而进行后两次(第二次和第三次)握手。 


    三、四次挥手

    因为 TCP 连接是全双工的。因此每一个方向都必须单独进行关闭这好比,我们打电话(全双工),正常的情况下(出于礼貌),通话的两方都要说再见后才干挂电话,保证通信两方都把话说完了才挂电话



    TCP 的四次握手是为了保证通信两方都关闭了连接,详细步骤例如以下:




    1)client A 在应用层调用close时会激发底层发送一个 FIN(tcp协议中FIN位置1、序号为M。结合上图分析)请求,用来关闭客户 A 到server B 的数据传送,clientA此时处于半关闭状态应用层无法接收数据但底层还能够接收数据)。


    2)server B 底层收到clientA的FIN时会做两件事

    2.1)第1件事:收到clientA的FIN时底层会主动回发一个ACK(tcp协议中ACK位置1。确认序号M+1

    2.2)第2件事:收到clientA的FIN时。导致serverB的应用层read()返回0(告诉serverB应用层:clientA关闭了


    3)serverB应用层调用close()激发底层给client A 发送一个 FIN(tcp协议中FIN位置1、序号为N),这是serverB已处于半关闭状态;


    4)client A 底层发 ACK(tcp协议中ACK位置1,确认序号N+1) 给serverB,这是clientA、serverB都处于全然关闭状态。回收对应的资源。





    为什么建立连接协议是三次握手。而关闭连接却是四次握手呢?


    这是由于服务端的 LISTEN 状态下的 SOCKET 当收到 SYN 报文的建连请求后,它能够把 ACK 和 SYN(ACK 起应答作用。而 SYN 起同步作用)放在一个报文里来发送。

    但关闭连接时,当收到FIN 报文通知时,假设能将ACK、FIN放在一个报文里那么就有了三次挥手。可是这是不可能。由于ACK是serverB一收到FIN报文底层就回发的,而serverB的FIN是应用层调用close()激发的。所以它这里的 ACK 报文和 FIN 报文在发送的时间上都是分开的,不可能同一时候发送


    为什么 TIME_WAIT 状态还须要等 2MS L后才干返回到 CLOSED 状态?


    这是由于尽管两方都允许关闭连接了,并且握手的 4 个报文也都协调和发送完成,按理能够直接回到 CLOSED 状态(就好比从 SYN_SEND 状态到 ESTABLISH 状态那样)。可是由于我们必需要假想网络是不可靠的,你无法保证你最后发送的 ACK 报文会一定被对方收到。因此对方处于 LAST_ACK 状态下的 SOCKET 可能会由于超时未收到 ACK 报文。而重发 FIN 报文。所以这个 TIME_WAIT 状态的作用就是用来重发可能丢失的 ACK 报文。(里面涉及的状态是什么意思,详情请看《TCP 通信过程中各步骤的状态》



  • 相关阅读:
    POJ 3253 Fence Repair
    POJ 2431 Expedition
    NYOJ 269 VF
    NYOJ 456 邮票分你一半
    划分数问题 DP
    HDU 1253 胜利大逃亡
    NYOJ 294 Bot Trust
    NYOJ 36 最长公共子序列
    HDU 1555 How many days?
    01背包 (大数据)
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6860790.html
Copyright © 2011-2022 走看看