对于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

posted @ 2019-11-20 17:08  IT实战家  阅读(502)  评论(0编辑  收藏  举报