zoukankan      html  css  js  c++  java
  • 对于TCP/IP协议的三次握手和四次挥手的理解

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/Freak_ysy/article/details/81543873

    因为很久之前被老师要求讲过这个问题,好久没有看,又有些迷糊了。只能写一篇博客来加强一下记忆
    TCP报文段首部格式的几个名词

        序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。
         确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。
        确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效
        同步SYN:连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。
        终止FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接

    ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。
    三次握手过程
           1.三次握手图片过程
          2.三次握手的文字过程

           (1)主机A向主机B发送TCP连接请求数据包,其中包含主机A的初始序列号seq(A)=x。(其中报文中同步标志位SYN=1,ACK=0,表示这是一个TCP连接请求数据报文;序号seq=x,表明传输数据时的第一个数据字节的序号是x)
        (2)主机B收到请求后,会发回连接确认数据包。(其中确认报文段中,标识位SYN=1,ACK=1,表示这是一个TCP连接响应数据报文,并含主机B的初始序列号seq(B)=y,以及主机B对主机A初始序列号的确认号ack(B)=seq(A)+1=x+1)
        (3)第三次,主机A收到主机B的确认报文后,还需作出确认,即发送一个序列号seq(A)=x+1;确认号为ack(A)=y+1的报文;

     
    四次挥手过程   
       1.四次挥手的图片过程
        
      2.四次挥手的文字过程

        (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状态,完成四次挥手,连接关闭

     
    问题:
    1.为什么是三次握手而不是两次握手或四次握手?

            简单点来说就是两次握手不能保证连接的稳定性,四次握手太浪费资源。

           正常情况下:A发出连接请求,但因为丢失了,故而不能收到B的确认。于是A重新发出请求,然后收到确认,建立连接,数据传输完毕后,释放连接,A发了2个,一个丢掉,一个到达,没有“已失效的报文段”    但是,某种情况下,A的第一个在某个节点滞留了,延误到达,本来这是一个早已失效的报文段,但是在A发送第二个,并且得到B的回应,建立了连接以后,这个报文段竟然到达了,于是B就认为,A又发送了一个新的请求,于是发送确认报文段,同意建立连接,假若没有三次的握手,那么这个连接就建立起来了(有一个请求和一个回应),此时,A收到B的确认,但A知道自己并没有发送建立连接的请求,因为不会理睬B的这个确认,于是呢,A也不会发送任何数据,而B呢却以为新的连接建立了起来,一直等待A发送数据给自己,此时B的资源就被白白浪费了。但是采用三次握手的话,A就不发送确认,那么B由于收不到确认,也就知道并没有要求建立连接。所以第三次握手,主机A发送一次确认是为了防止:如果客户端迟迟没有收到服务器返回的确认报文,这时他会放弃连接,重新启动一条连接请求;但问题是:服务器不知客户端没收到,所以他会收到两个连接请求,白白浪费了一条连接开销。而四次或更多次的握手,则是浪费资源,因为三次握手已经可以达到的效果没有必要再去多次连接

           上次在知乎上看到一个很有意思的解释:就说两个人视频通话,如果是三次握手:

             男:你听的到吗?

             女:我听得到,听得到我的声音吗?

             男:我听的到你的,blablabla。。。。

           如果是两次握手:

                男:你听的到吗?

                女:听得到。

                男:你听的到吗?

                女:听得到

                男:你听得到吗?

                女:。。。有病吧。

          如果是四次握手:

                男:你听的到吗?

                女:听得到,你听得到我说的么。

                男:听的到,你听得到我说得么。

                女:。。。。不想和傻子说话。
    2.为什么连接的时候需要三次握手,而断开的时候要四次挥手

          三次握手可以理解为:

               A--请求-->B

              A<--确认--B

             A<--请求--B

             A--确认-->B

    只是对于三次握手来说中间的两个步骤是可以合并成一次的,而对于四次挥手来说则是不可以合并,因为四次挥手发送的FIN报文仅仅表示对方不再发送数据了但是还能接收数据,所以要等自己这边发出FIN之后,才能close。具体:

          因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
    3.为什么client要先进入TIME-WAIT状态,等待2MSL时间后才进入CLOSED状态?

        为了保证server能收到client的确认应答。 若client发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,server等待超时后就会重新发送连接释放请求,但此时client已经关闭了,不会作出任何响应,因此server永远无法正常关闭。
    ————————————————
    版权声明:本文为CSDN博主「Freak_ysy」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/freak_ysy/article/details/81543873

  • 相关阅读:
    Two Sum II
    Subarray Sum
    Intersection of Two Arrays
    Reorder List
    Convert Sorted List to Binary Search Tree
    Remove Duplicates from Sorted List II
    Partition List
    Linked List Cycle II
    Sort List
    struts2结果跳转和参数获取
  • 原文地址:https://www.cnblogs.com/lishiqi-blog/p/11898982.html
Copyright © 2011-2022 走看看