• TCP连接和断开


    参考博文

    https://www.cnblogs.com/Jessy/p/3535612.html

    https://blog.csdn.net/cjsycyl/article/details/19327869

    https://blog.csdn.net/qq_35546040/article/details/80280900

    https://www.cnblogs.com/grglym/p/7788175.html

    https://www.cnblogs.com/onlysun/p/4520553.html

    名词解释

     1、 MSL 是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为tcp报文 (segment)是ip数据报(datagram)的数据部分,具体称谓请参见《数据在网络各层中的称呼》一文;

       2、ip头中有一个TTL域,TTL是 time to live的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个ip数据报可以经过的最大路由数,每经 过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

        TTL与MSL是有关系的但不是简单的相等的关系,MSL要大于等于TTL。

       3、 RTT是客户到服务器往返所花时间(round-trip time,简称RTT),TCP含有动态估算RTT的算法。TCP还持续估算一个给定连接的RTT,这是因为RTT受网络传输拥塞程序的变化而变化

       4、2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握 手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个 ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态 时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置 SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。对于TCP中的各种控制字段,接下来进行具体说明。

    二、TCP控制字段标志:URG、ACK、PSH、RST、SYN、FIN

    在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG.
    其中,对于我们日常的分析有用的就是前面的五个字段。

    它们的含义是:

    URG:Urget pointer is valid (紧急指针字段值有效)

    SYN: 表示建立连接

    FIN: 表示关闭连接

    ACK: 表示响应

    PSH: 表示有 DATA数据传输

    RST: 表示连接重置。

           其中,ACK是可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应,如果只是单个的一个SYN,它表 示的只是建立连接。TCP的几次握手就是通过这样的ACK表现出来的。但SYN与FIN是不会同时为1的,因为前者表示的是建立连接,而后者表示的是断开 连接。RST一般是在FIN之后才会出现为1的情况,表示的是连接重置。一般地,当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接;而 当出现SYN和SYN+ACK包时,我们认为客户端与服务器建立了一个连接。PSH为1的情况,一般只出现在 DATA内容不为0的包中,也就是说PSH为1表示的是有真正的TCP数据包内容被传递。

          TCP产生 RST响应的情况(属于硬错误):

           四次握手不是关闭 TCP连接的唯一方法. 有时,如果主机需要尽快关闭连接(或连接超时,端口或主机不可达),RST (Reset)包将被发送. 注意在,由于RST包不是TCP连接中的必须部分, 可以只发送RST包(即不带ACK标记). 但在正常的TCP连接中RST包可以带ACK确认标记
          1. syn发送到服务器主机,但是目的端口并未运行。则产生一个ECONRFUSED错误。客户端立即返回。比如telnet 192.168.1.55 8889,条件:55主机在局域网上并且可达(也可以换成可以到达的网络ip地址),但是8889这个端口并未使用(可能服务器已经关闭),则服务器(对 方主机tcp内核)发送一个rst相应给客户端,于是客户端立即关闭。 注意一下,如果输入的网络ip不可达的话,客户端将会持续发送syn,最后产生一个etimeout的错误,大概75秒左右。这个时候客户端的默认网关 (192.168.1.1 211.2.2.2)因为找不到下一路由,路由器(或者再过几跳的路由器)会产生一个EHOSTUNREACH响应给客户端(注 意,ENETUNREACH和EHOSTUNREACH通常被认为是一个错误,因为ENETUNREACH一般当作已过时),由于这是个软错误(有可能是 网络暂时不通造成的)。客户端会重发syn直到超时。
            所以会有 telnet 192.168.1.55 8888  主机存在,但是端口未开,ECONRFUSED错误,立刻返回
                     telnet 192.168.1.56 *     主机不存在,UNROUTETOHOST错误,立刻返回
                     telnet 211.1.1.5    *     主机不存在,etimeout错误
     
          2. 最简单的情况,服务器主动发送rst给客户端关闭连接。客户端read write直接返回rst错误。
     
          3. 服务器收到一个不存在的连接返回rst响应。比如,服务器重启之后,先前的一个已连接的客户端毫不之情的情况下,这就是半闭连接(跟半开连接最大的不同是,半闭连接是不能使用的,半开连接可以使用)。
           此时,如果客户端read的话(接收缓冲无数据)产生一个EPEERRST错误
                   如果客户端write的话且发送数据小于发送缓冲区剩余容量时,第一次write成功,第二次write或者read的时候就会产生一个 EPEERRST的错误。因为write发送数据是直接把要发送的数据拷贝到内核的tcp发送缓冲区就立刻返回成功的。当然拷贝之前会先检查一下tcp连 接有无错误。所以第二次发送或者接收的时候,发现连接上已经有了EPEERRST的错误,所以就返回错误(话说回来,第一次发送的数据实际上根本就没有发 送成功,对方根本就没接受它)

     TCP建立连接:三次握手

    TCP断开连接:四次挥手

     

    TCP建立的三次握手:

      1、发送端发送一个SYN报文段(SYN位被置位),SYN中包含TCP目的端口和发送端的初始序列号(图中ISN(c)),同时携带着TCP选项数据。

      2、接收端收到发送端连接请求后,接收端发送自己SYN报文段(包含ISN(s)),同时对发送端的SYN进行确认,如前所述,接收端发送的ACK是ISN(c)+1。此时ACK位与SYN位都被置位。接收端发送SYN+ACK到发送端。

      3、发送端接收到接收端的SYN+ACK数据后,对ISN(s)进行确认,发送ACK为ISN(s)+1的报文段给接收端。

    TCP断开的四次握手:

      1、TCP协议规定通过发送一个FIN段(FIN被置位)来发起关闭操作,图3中发送端发送FIN段给接收端,告知它数据已发送完毕,请求断开TCP连接。同时FIN报文段还包含着对最近收到的数据进行ACK。

      2、接收端接收端FIN报文段后,对FIN进行确认,发送ACK=k+1给发送端。

      3、接收端将连接关闭发送给上层应用程序,由应用程序发起连接关闭操作。此时接收端由被动关闭连接壮成主动,并发送FIN报文段给发送端。报文的序列号为L(这里也可看出上一步骤中发送ACK序列号也为L,因为ACK不占用序列号,所以这里的FIN的序列号也为L)。

      4、发送端接收到FIN后,发送回ACK给接收端后,TCP连接终止。如果FIN丢失,发送FIN的那端需要重新发送FIN,知道接收到ACK为止。

     一、建立TCP连接
      三次握手:所谓的“三次握手”即对每次发送的数据量是怎样跟踪进行协商使数据段的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送、接收完毕后何时撤消联系,并建立虚连接。
      为了提供可靠的传送,TCP在发送新的数据之前,以特定的顺序将数据包的序号,并需要这些包传送给目标机之后的确认消息。TCP总是用来发送大批量的数据。当应用程序在收到数据后要做出确认时也要用到TCP。
      位码即TCP标志位,有6种标示:SYN(synchronous建立联机)、ACK(acknowledgement确认)、PSH(push传送) 、FIN(finish结束)、RST(reset重置)、URG(urgent紧急)
      确认号:其数值等于发送方的发送序号 +1(即接收方期望接收的下一个序列号)。
      详细过程如下:
      第一次:
      第一次握手:建立连接时,客户端发送SYN包(SYN=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
      第二次:
      第二次握手:服务器收到SYN包,必须确认客户的SYN(ACK=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。
      第三次:
      第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
    未连接队列:

       在三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(SYN=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户发 出确认,正在等待客户的确认包。这些条目所标识的连接在服务器处于 SYN_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED状态。

      Backlog参数:

      表示内核为相应套接字排队的最大连接个数。仅对于backlog来说,我们需要取一个比较大的值以应对大量的服务请求。

      服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同。

      半连接存活时间

      是指半连接队列的条目存活的最长时间,也即服务器从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。

      二、关闭TCP连接:

      由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个FIN只意味着

    这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

      TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。

      步骤如下:

      第一步:当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段(FIN表示英文finish)。

      第二步:主机B收到这个FIN报文段之后,并不立即用FIN报文段回复主机A,而是先向主机A发送一个确认序号ACK,同时通知自己相应的应用程序:对方要求关闭连接(先

    发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。

      第三步:主机B的应用程序告诉TCP:我要彻底的关闭连接,TCP向主机A送一个FIN报文段。

      第四步:主机A收到这个FIN报文段后,向主机B发送一个ACK表示连接彻底释放。

      在网络编程时,常常会创建套接字,套接字使用完成后常常关闭套接字,那么关闭Socket时客户端和服务端究竟做了什么?

      关闭socket分为主动关闭(Active closure)和被动关闭(Passive closure)两种情况。

      主动关闭是指有本地主机主动发起的关闭;而被动关闭则是指本地主机检测到远程主机发起关闭之后,作出回应,从而关闭整个连接。

      被动关闭的情况下:

      客户端发起中断连接请求,也就是发送FIN报文。

      服务器接到FIN报文后,报文意思是说“我客户端没有数据要发给你了,但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据”。

      所以服务器先发送ACK,告诉客户端:“你的请求我收到了,但是我还没准备好,请继续你等我的消息"。

      这个时候客户端就进入FIN_WAIT状态,继续等待服务器的FIN报文。

      当服务器确定数据已发送完成,则向客户端发送FIN报文,告诉客户端:“好了,我这边数据发完了,准备好关闭连接了"。

      Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕服务器不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果服务器没有收

    到ACK则可以重传“。

      Server端收到ACK后,"就知道可以断开连接了"。

     在TIME_WAIT状态中,如果TCP client端最后一次发送的ACK丢失了,它将重新发送。TIME_WAIT状态中所需要的时间是依赖于实现方法的。典型的值为30秒、1分钟和2分钟。等待之后连接正式关闭,并且所有的资源(包括端口号)都被释放。

      问题1:为什么连接的时候是三次握手,关闭的时候却是四次握手?
      因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同 步的。但是关闭连接时,当Server端

    收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你 发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我

    才能发送FIN报文,因此不能一起发送。故需要四步握手。

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

      虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发

    可能丢失的ACK报文。

      三、winsocks2关闭套接字的函数有:closesocket,shutdown,WSASendDisconnect.。

      int closesocket( SOCKET s)的作用是关闭指定的socket,并且回收其所有的资源。

      int shutdown( SOCKET s,  int how)则是用于任何类型的套接口禁止接收、禁止发送或禁止收发,但并不对资源进行回收。

      how参数为0时,则该套接口上的后续接收操作将被禁止。这对于低层协议无影响。

      how为1时,则禁止后续发送操作。对于TCP,将发送FIN。

      how为2时,则同时禁止收和发。

     
  • 相关阅读:
    【前端学习笔记】函数柯里化(自网易云课堂)
    【前端学习笔记】call、apply、bind方法
    【前端学习笔记】arguments相关
    【前端学习笔记】函数定义、函数调用、this
    【前端学习笔记】闭包的作用及案例
    【前端学习笔记】利用iframe实现表单的无刷新提交案例
    【前端学习笔记】JavaScript 常用方法兼容性封装
    【前端学习笔记】JavaScript 小案例合集
    【前端学习笔记】JavaScript JSON对象相关操作
    牛客多校第10场J Wood Processing 分治优化/斜率优化 DP
  • 原文地址:https://www.cnblogs.com/heroinss/p/10642455.html
Copyright © 2020-2023  润新知