zoukankan      html  css  js  c++  java
  • TCP三次握手和四次挥手的全过程

    TCP传输连接分为3个阶段,分别是:连接建立、数据传送、连接释放。

    连接建立要经过三次握手:

    三次握手:

    第一次握手:客户端发送一个syn包给服务器,并进入同步已发送(SYN_SEND)状态,等待服务器确认。这个时候SYN=1,seq=x。
    第二次握手:服务器收到客户端发来的syn包,然后进行确认,同时自己也发送一个SYN+ACK包给客户端,然后服务器进入同步收到(SYN_RECV)状态。这个时候SYN=1,ACK=1,seq=y,ack=x+1。
    第三次握手:客户端收到服务器的SYN+ACK包后,向服务器发送确认包ACK,这个包发送完毕后,客户端和服务器进入到已建立连接(ESTABLISHED)状态,完成三次握手,开始传输数据。这个时候ACK=1,seq=x+1,ack=y+1。

    (1)为什么会采用三次握手,若采用二次握手可以吗?

    答:采用三次握手是为了防止失效的连接请求报文段突然又传送到服务器端,因而产生错误。失效的连接请求报文段是指:客户端发出的连接请求没有收到服务器的确认,于是经过一段时间后,客户端又重新向服务器发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,客户端第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到服务器,服务器以为是客户端又发起的新连接,于是服务器同意连接,并向客户端发回确认,但是此时客户端根本不会理会,服务器就一直在等待客户端发送数据,导致服务器的资源浪费。

    四次挥手:

    四次挥手:

    连接释放过程

    第一次挥手:当数据传输结束以后,客户端的应用进程发出连接释放报文段,并停止发送数据,其首部:FIN=1,seq=u。

    第二次挥手:服务器端收到连接释放报文段之后,发出确认报文,其首部:ACK=1,seq=v,ack=u+1。此时本次连接就进入了半关闭状态,客户端不再向服务器发送数据。而服务器端仍会继续发送。

    第三次挥手:若服务器已经没有要向客户端发送的数据,其应用进程就通知服务器释放TCP连接。这个阶段服务器所发出的最后一个报文的首部应为:FIN=1,ACK=1,seq=w,ack=u+1。

    第四次挥手:客户端收到连接释放报文段之后,必须发出确认:ACK=1,seq=u+1,ack=w+1。 再经过2MSL(Maximum Segment Lifetime最长报文寿命)后,本次TCP连接真正结束,通信双方完成了他们的告别。

    在这个过程中,通信双方的状态如下图,其中:ESTAB-LISHED:连接建立状态、FIN-WAIT-1:终止等待1状态、FIN-WAIT-2:终止等待2状态、CLOSE-WAIT:关闭等待状态、LAST-ACK:最后确认状态、TIME-WAIT:时间等待状态、CLOSED:关闭状态

    (1)在结束连接的过程中,为什么在收到服务器端的连接释放报文段之后,客户端还要继续等待2MSL之后才真正关闭TCP连接呢?

    这里有两个原因:

    第一个是:需要保证服务器端收到了客户端的最后一条确认报文。假如这条报文丢失,服务器没有接收到确认报文,就会对连接释放报文进行超时重传,而此时客户端连接已关闭,无法做出响应,就造成了服务器端不停重传连接释放报文,而无法正常进入关闭状态的状况。而等待2MSL,就可以保证服务器端收到了最终确认;若服务器端没有收到,那么在2MSL之内客户端一定会收到服务器端的重传报文,此时客户端就会重传确认报文,并重置计时器。

    第二个是:存在一种“已失效的连接请求报文段”,需要避免这种报文端出现在本连接中,造成异常。这种“已失效的连接请求报文段”是这么形成的:假如客户端发出了连接请求报文,然而服务器端没有收到,于是客户端进行超时重传,再一次发送了连接请求报文,并成功建立连接。然而,第一次发送的连接请求报文并没有丢失,只是在某个网络结点中发生了长时间滞留,随后,这个最初发送的报文段到达服务器端,会使得服务器端误以为客户端发出了新的请求,造成异常。

    (2)为什么建立连接是三次握手,而关闭连接却是四次挥手呢? 
    这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。

    序列号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表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接

        PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。

    参考链接:

    https://blog.csdn.net/qq_38950316/article/details/81087809

    https://cloud.tencent.com/developer/news/257281

  • 相关阅读:
    ConcurrentHashMap的使用和原理
    记录下项目中常用到的JavaScript/JQuery代码一(大量实例)
    layer ui插件显示tips时,修改字体颜色
    flash上传文件,如何解决跨域问题
    ubuntu下的mv命令
    Semantic 3D
    shellnet运行train_val_seg.py
    Tensorflow的不足之处
    用pip命令把python包安装到指定目录
    ubuntu建立文件或者文件夹软链接
  • 原文地址:https://www.cnblogs.com/linliquan/p/10555999.html
Copyright © 2011-2022 走看看