精华内容
下载资源
问答
  • 网上查了一下端口状态的资料,我下面总结了一下,自己学习学习: TCP状态转移要点 TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,...

    本文根据众多互联网博客内容整理后形成,引用内容的版权归原始作者所有,仅限于学习研究使用

    网上查了一下端口状态的资料,我下面总结了一下,自己学习学习:

    TCP状态转移要点
        TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源。在众多TCP状态中,最值得注意的状态有两个:CLOSE_WAIT和TIME_WAIT。  
     
    1、LISTENING状态
      FTP服务启动后首先处于侦听(LISTENING)状态。

    2、ESTABLISHED状态
      ESTABLISHED的意思是建立连接。表示两台机器正在通信。

    3、CLOSE_WAIT

        对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT 此时我方要调用close()来使得连接正确关闭

    4、TIME_WAIT

        我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAITTCP协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT状态的连接占用的资源不会被内核释放,所以作为服务器,在可能的情况下,尽量不要主动断开连接,以减少TIME_WAIT状态造成的资源浪费。

        目前有一种避免TIME_WAIT资源浪费的方法,就是关闭socket的LINGER选项。但这种做法是TCP协议不推荐使用的,在某些情况下这个操作可能会带来错误。

    1. socket的状态

    1.1 状态说明

    CLOSED 没有使用这个套接字[netstat 无法显示closed状态]
    LISTEN 套接字正在监听连接[调用listen后]
    SYN_SENT 套接字正在试图主动建立连接[发送SYN后还没有收到ACK]
    SYN_RECEIVED 正在处于连接的初始同步状态[收到对方的SYN,但还没收到自己发过去的SYN的ACK]
    ESTABLISHED 连接已建立
    CLOSE_WAIT 远程套接字已经关闭:正在等待关闭这个套接字[被动关闭的一方收到FIN]
    FIN_WAIT_1 套接字已关闭,正在关闭连接[发送FIN,没有收到ACK也没有收到FIN]
    CLOSING 套接字已关闭,远程套接字正在关闭,暂时挂起关闭确认[在FIN_WAIT_1状态下收到被动方的FIN]
    LAST_ACK 远程套接字已关闭,正在等待本地套接字的关闭确认[被动方在CLOSE_WAIT状态下发送FIN]
    FIN_WAIT_2 套接字已关闭,正在等待远程套接字关闭[在FIN_WAIT_1状态下收到发过去FIN对应的ACK]
    TIME_WAIT 这个套接字已经关闭,正在等待远程套接字的关闭传送[FIN、ACK、FIN、ACK都完毕,这是主动方的最后一个状态,在过了2MSL时间后变为CLOSED状态]

    1.2 状态变迁图

    摘自《UNIX 网络编程 卷1:套接字联网API》 P35

     

    2. TCP的三次握手和四次挥手

    2.1 总结图

    左边为客户端的状态转变,后边为服务器的状态转变

    2.2 说明

    2.2.1   connect返回-1

                 errno=110(ETIMEDOUT),当服务器端网线拔了的时候,客户端发送SYN过去就会收不到ACK,因此就会出现这个错误,1分钟内就会返  回这个错误。

                 errno=111(ECONNREFUSED),当服务器未listen时,就会报这个错

    2.2.2 ESTABLISHED不一定真的establish

                  会出现这种情况:client为ESTABLISHED状态而server为SYN_REVD状态。

                 这是因为LINUX不像其他操作系统在收到SYN为该连接立马分配一块内存空间用于存储相关的数据和结构,而是延迟到接收到client的ACK,即三次握手    真正完成后才分配空间,这是为了防范SYN flooding攻击。 如果是这种情况,那么就会出现client端未ESTABLISHED状态,server为SYN_RECV状态。   

                 并且server的SYN_RECV状态在一定时间后会消失,client的established状态也会消失。这是因为server在SYN_RECV状态时,会像client发送多次的SYN+ACK(因为他以为自己的这个包对方没收到),发送的次数定义在/proc/sys/net/ipv4/tcp_synack_retries中,默认为5.在发送5次之后还没有收到ACK,就将其回收了,所以用netstat查看就看不到这个SYN_RECV状态了。并且会像client发送RST信号。这就会导致client的这种半连接最后也会消失。这个可以通过tcpdump抓包得到(最好知道src这样看到的包比较集中)。

     

    TIME_WAIT处理方法

      实现的目标就是不要让处于TIME_WAIT的端口占满所有本地端口,导致没有新的本地端口用来创建新的客户端。
      1. 别让客户端的速率太快
      似乎上面的案例告诉我们别优化用力过猛,否则容易扯到蛋……将客户端请求的速率降下来就可以避免端时间占用大量的端口,吞吐量限制就是470tps或者235tps,具体根据系统TIME_WAIT默认时长决定,如果考虑到其他服务正常运行这个值还要保守一些才行;此外还需要注意,如果客户端和服务端增加了一层NAT或者L7负载均衡,那么这个限制可能会在负载均衡器上面;
      2. 客户端改成长连接的形式
      长连接效率高又不会产生大量TIME_WAIT端口。目前对我们来说还是不太现实的,虽然HTTP支持长连接,但是CGI调用应该是不可能的了,除非用之前的介绍的方式将CGI的请求转换成HTTP服务来实现。对于一般socket直连的程序来说,短连接改成长连接就需要额外的封装来标识完整请求在整个字节流中的起始位置,需要做一些额外的工作;
      3. SO_LINGER选项
      通常我们关闭socket的时候,即使该连接的缓冲区有数据要发送,close调用也会立即返回,TCP本身会尝试发送这些未发送出去的数据,只不过应用程序不知道也无法知道是否发送成功过了。如果我们将套接字设置SO_LINGER这个选项,并填写linger结构设置参数,就可以控制这种行为:
      如果linger结构的l_onoff==0,则linger选项就被关闭,其行为就和默认的close相同;如果打开,那么具体行为依据另外一个成员l_linger的值来确定:如果l_linger!=0,则内核会将当前close调用挂起,直到数据都发送完毕,或者设置的逗留时间超时返回,前者调用会返回0并且正常进入TIME_WAIT状态,后者调用会返回EWOULDBLOCK,所有未发送出去的数据可能会丢失(此处可能会向对端发送一个RST而快速关闭连接);如果l_linger==0,则直接将缓冲区中未发送的数据丢弃,且向对等实体发送一个RST,自己不经过TIME_WAIT状态立即关闭连接。
      我们都认为TIME_WAIT是TCP机制的正常组成部分,应用程序中不应该依赖设置l_linger=0这种机制避免TIME_WAIT。
      4. 修改系统参数
      (a). 增加本地端口范围,修改net.ipv4.ip_local_port_range,虽然不能解决根本问题但情况可以得到一定的缓解;
      (b). 缩短TIME_WAIT的时间。这个时长在书中描述到RFC推荐是2min,而BSD实现通常是30s,也就说明这个值是可以减小的,尤其我们用在内网通信的环境,数据包甚至都流不出路由器,所以根本不需要设置那么长的TIME_WAIT。这个很多资料说不允许修改,因为是写死在内核中的;也有说可以修改netfilter.ip_conntrack_tcp_timeout_time_wait(新版本nf_conntrack_tcp_timeout_time_wait)的,他们依赖于加载nf_conntract_ipv4模块,不过我试了一下好像不起作用。
      (c). 像之前在项目中推荐的,做出如下调整

    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_timestamps=1
    net.ipv4.tcp_tw_recycle=1

           很多文献说这种设置是不安全的,所以在测试环境以外就别尝试了,因为这些选项还涉及到timestamp特性,我还不清楚什么回事,后面有时间再看什么吧。
      我们在开发服务端的时候,通常都会设置SO_REUSEADDR这个选项。其实像上面描述到的,该选项也牵涉到侦听socket端口处于TIME_WAIT的情况,设置这个选项将允许处于TIME_WAIT的端口进行绑定

     

    另外一文:

            记得以前面试的时候被面试官问起TIME_WAIT有什么痛点,当时只记得TCP三次握手、四次挥手之类的,至于其中的某个状态还真是记不起来,之前也没有过多关注过,还有对于拥塞控制的概念也比较模糊。

    TCP报文格式

    TCP大家都知道是什么东西,这个协议的具体报文格式如下:

    标志位

    1. URG:指示报文中有紧急数据,应尽快传送(相当于高优先级的数据)。
    2. PSH:为1表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
    3. RST:TCP连接中出现严重差错(如主机崩溃),必须释放连接,在重新建立连接。
    4. FIN:发送端已完成数据传输,请求释放连接。
    5. SYN:处于TCP连接建立过程。 (Synchronize Sequence Numbers)
    6. ACK:确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。


    窗口

          滑动窗口大小,这个字段是接收端用来告知发送端自己还有多少缓冲区可以接受数据。于是发送端可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。(以此控制发送端发送数据的速率,从而达到流量控制。)窗口大小时一个16bit字段,因而窗口大小最大为65535。

    头部长度(首部长度)

          由于TCP首部包含一个长度可变的选项和填充部分,所以需要这么一个值来指定这个TCP报文段到底有多长。或者可以这么理解:就是表示TCP报文段中数据部分在整个TCP报文段中的位置。该字段的单位是32位字,即:4个字节。TCP的滑动窗口大小实际上就是socket的接收缓冲区大小的字节数。

    选项和填充部分

          TCP报文的字段实现了TCP的功能,标识进程、对字节流拆分组装、差错控制、流量控制、建立和释放连接等。其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,那么选项部分最长为:(2^4-1)*(32/8)-20=40字节。

    三次握手

     


          最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。

          TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了**LISTEN(监听)**状态;
          TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这是报文首部中的**同部位SYN=1,同时选择一个初始序列号 seq=x **,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。
          TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了**SYN-RCVD(同步收到)**状态。这个报文也不能携带数据,但是同样要消耗一个序号。
          TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入**ESTABLISHED(已建立连接)**状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。
          当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。
          三次握手主要目的是:信息对等和防止超时。防止超时导致脏连接。如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。

    四次挥手


          数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。

    1. 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
    2. 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
    3. 客户端收到服务器的确认请求后,此时,客户端就进入**FIN-WAIT-2(终止等待2)**状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
    4. 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了**LAST-ACK(最后确认)**状态,等待客户端的确认。
    5. 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
    6. 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

          TIME_WAIT:主动要求关闭的机器表示收到了对方的FIN报文,并发送出了ACK报文,进入TIME_WAIT状态,等2MSL后即可进入到CLOSED状态。如果FIN_WAIT_1状态下,同时收到待FIN标识和ACK标识的报文时,可以直接进入TIME_WAIT状态,而无需经过FIN_WAIT_2状态。

          CLOSE_WAIT:被动关闭的机器收到对方请求关闭连接的FIN报文,在第一次ACK应答后,马上进入CLOSE_WAIT状态。这种状态其实标识在等待关闭,并且通知应用发送剩余数据,处理现场信息,关闭相关资源。

    为什么客户端最后还要等待2MSL?

          MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。**第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失。**站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。如果客户端收到服务端的FIN+ACK报文后,发送一个ACK给服务端之后就“自私”地立马进入CLOSED状态,可能会导致服务端无法确认收到最后的ACK指令,也就无法进入CLOSED状态,这是客户端不负责任的表现。**第二,防止失效请求。**防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

           在TIME_WAIT状态无法真正释放句柄资源,在此期间,Socket中使用的本地端口在默认情况下不能再被使用。该限制对于客户端机器来说是无所谓的,但对于高并发服务器来说,会极大地限制有效连接的创建数量,称为性能瓶颈。所以建议将高并发服务器TIME_WAIT超时时间调小。RFC793中规定MSL为2分钟。但是在当前的高速网络中,2分钟的等待时间会造成资源的极大浪费,在高并发服务器上通常会使用更小的值。
          在服务器上通过变更/etc/sysctl.conf文件来修改该默认值net.ipv4.tcp_fin_timout=30(建议小30s)。修改完之后执行 /sbin/sysctl -p 让参数生效。
          通过如下命令查看各连接状态的技术情况:

    [root@node1 ~]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
    TIME_WAIT 63
    ESTABLISHED 13

    为什么建立连接是三次握手,关闭连接确是四次挥手呢?

          建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

    滑动窗口

          TCP滑动窗口技术通过动态改变窗口大小来调节两台主机间数据传输。每个TCP/IP主机支持全双工数据传输,因此TCP有两个滑动窗口:一个用于接收数据,另一个用于发送数据。TCP使用肯定确认技术,其确认号指的是下一个所期待的字节。 假定发送方设备以每一次三个数据包的方式发送数据,也就是说,窗口大小为3。发送方发送序列号为1、2、3的三个数据包,接收方设备成功接收数据包,用序列号4确认。发送方设备收到确认,继续以窗口大小3发送数据。当接收方设备要求降低或者增大网络流量时,可以对窗口大小进行减小或者增加,本例降低窗口大小为2,每一次发送两个数据包。当接收方设备要求窗口大小为0,表明接收方已经接收了全部数据,或者接收方应用程序没有时间读取数据,要求暂停发送。发送方接收到携带窗口号为0的确认,停止这一方向的数据传输。当链路变好了或者变差了这个窗口还会发生变话,并不是第一次协商好了以后就永远不变了。

          滑动窗口协议,是TCP使用的一种流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输。 只有在接收窗口向前滑动时(与此同时也发送了确认),发送窗口才有可能向前滑动。收发两端的窗口按照以上规律不断地向前滑动,因此这种协议又称为滑动窗口协议。

          流量控制:端到端,接收端的应用层处理速度决定和网速无关,由接收端返回的rwnd控制

    cwnd:发送端窗口( congestion window )
    rwnd:接收端窗口(receiver window)

    拥塞控制

          拥塞控制: 发送端主动控制cwnd,有慢启动(从cwnd初始为1开始启动,指数启动),拥塞避免(到达ssthresh后,为了避免拥塞开始尝试线性增长),快重传(接收方每收到一个报文段都要回复一个当前最大连续位置的确认,发送方只要一连收到三个重复确认就知道接收方丢包了,快速重传丢包的报文,并TCP马上把拥塞窗口 cwnd 减小到1),快恢复(直接从ssthresh线性增长)。

          如果网络上的延时突然增加,那么TCP对这个事作出的应对只有重传数据,但是重传会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,于是这个情况就会进入恶性循环被不断地放大。试想一下,如果一个网络内有成千上万的TCP连接都这么行事,那么马上就会形成“网络风暴”,TCP这个协议就会拖垮整个网络。所以TCP不能忽略网络上发生的事情,而无脑地一个劲地重发数据,对网络造成更大的伤害。对此TCP的设计理念是:TCP不是一个自私的协议,当拥塞发生的时候,要做自我牺牲。就像交通阻塞一样,每个车都应该把路让出来,而不要再去抢路了。

    慢启动

          只有在TCP连接建立和网络出现超时时才使用。每经过一个传输轮次,拥塞窗口 cwnd 就加倍。一个传输轮次所经历的时间其实就是往返时间RTT。不过“传输轮次”更加强调:把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。另外,慢开始的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置cwnd=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大cwnd。

          为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量(如何设置ssthresh)。慢开始门限ssthresh的用法如下:

    1. 当 cwnd < ssthresh 时,使用上述的慢开始算法。
    2. 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
    3. 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞控制避免算法。

          拥塞避免算法:让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

          无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。

          当TCP连接进行初始化时,把拥塞窗口cwnd置为1。前面已说过,为了便于理解,图中的窗口单位不使用字节而使用报文段的个数。慢开始门限的初始值设置为16个报文段,即 cwnd = 16 。
           在执行慢开始算法时,拥塞窗口 cwnd 的初始值为1。以后发送方每收到一个对新报文段的确认ACK,就把拥塞窗口值另1,然后开始下一轮的传输(图中横坐标为传输轮次)。因此拥塞窗口cwnd随着传输轮次按指数规律增长。当拥塞窗口cwnd增长到慢开始门限值ssthresh时(即当cwnd=16时),就改为执行拥塞控制算法,拥塞窗口按线性规律增长。
          假定拥塞窗口的数值增长到24时,网络出现超时(这很可能就是网络发生拥塞了)。更新后的ssthresh值变为12(即变为出现超时时的拥塞窗口数值24的一半),拥塞窗口再重新设置为1,并执行慢开始算法。当cwnd=ssthresh=12时改为执行拥塞避免算法,拥塞窗口按线性规律增长,每经过一个往返时间增加一个MSS的大小。
          强调:“拥塞避免”并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。“拥塞避免”是说在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。

           如果发送方设置的超时计时器时限已到但还没有收到确认,那么很可能是网络出现了拥塞,致使报文段在网络中的某处被丢弃。这时,TCP马上把拥塞窗口 cwnd 减小到1,并执行慢开始算法,同时把慢开始门限值ssthresh减半。这是不使用快重传的情况。快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。

           接收方收到了M1和M2后都分别发出了确认。现在假定接收方没有收到M3但接着收到了M4。显然,接收方不能确认M4,因为M4是收到的失序报文段。根据可靠传输原理,接收方可以什么都不做,也可以在适当时机发送一次对M2的确认。但按照快重传算法的规定,接收方应及时发送对M2的重复确认,这样做可以让发送方及早知道报文段M3没有到达接收方。发送方接着发送了M5和M6。接收方收到这两个报文后,也还要再次发出对M2的重复确认。这样,发送方共收到了接收方的四个对M2的确认,其中后三个都是重复确认。快重传算法还规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必继续等待M3设置的重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约20%。

          与快重传配合使用的还有快恢复算法,其过程有以下两个要点:

    1. 当发送方连续收到三个重复确认,就执行“乘法减小”算法,把慢启动门限ssthresh减半。这是为了预防网络发生拥塞。请注意:接下去不执行慢开始算法。
    2. 由于发送方现在认为网络很可能没有发生拥塞,因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为慢开始门限ssthresh减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。

          上图给出了快重传和快恢复的示意图,并标明了“TCP Reno版本”。区别:新的 TCP Reno 版本在快重传之后采用快恢复算法而不是采用慢开始算法。

    发送方窗口的上限值 = Min [ rwnd, cwnd ]

    当rwnd < cwnd 时,是接收方的接收能力限制发送方窗口的最大值。
    当cwnd < rwnd 时,则是网络的拥塞限制发送方窗口的最大值。

    差错控制

    TCP使用差错控制来提供可靠性。差错控制包括以下的一些机制:检测和重传受到损伤的报文段、重传丢失的报文段、保存失序到达的报文段直至缺失的报文到期,以及检测和丢弃重复的报文段。TCP通过三个简单的工具来完成其差错控制:检验和、确认以及超时。


    参考:

    https://hiddenpps.blog.csdn.net/article/details/84001583 

     

    请我喝咖啡

    如果觉得文章写得不错,能对你有帮助,可以扫描我的微信二维码请我喝咖啡哦~~哈哈~~

     

    展开全文
  • time wait和close wait

    2017-03-19 13:14:17
    一 查看方法  http://blog.csdn.net/qq_37023538/article/details/63008901 二 介绍time wait和close wait    客户端TCP状态:  CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
    一 查看方法
       http://blog.csdn.net/qq_37023538/article/details/63008901

    二 介绍time wait和close wait

      

       客户端TCP状态:        
       CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
       服务器TCP状态:      
       CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
       TIME_WAIT 
       是主动关闭链接时形成的,等待2MSL时间,约4分钟。主要是防止最后一个ACK丢失。  
       由于TIME_WAIT 的时间会非常长,因此server端应尽量减少主动关闭连接
       CLOSE_WAIT
       是被动关闭连接是形成的。根据TCP状态机,服务器端收到客户端发送的FIN,则按照TCP实现发送ACK,因此进入CLOSE_WAIT状态。
       但如果服务器端不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接。
       此时,可能是系统忙于处理读、写操作,而未将已收到FIN的连接,进行close。此时,recv/read已收到FIN的连接socket,会返回0。
    三 解决方法:
       TIME_WAIT:表示主动关闭,通过优化系统内核参数解决。
       CLOSE_WAIT:表示被动关闭,需要从程序本身出发。
       TIME_WAIT
       修改/etc/sysctl.conf文件:
       #表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭  
       net.ipv4.tcp_syncookies = 1  
       #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭  
       net.ipv4.tcp_tw_reuse = 1  
       #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭  
       net.ipv4.tcp_tw_recycle = 1
       #表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间  
       net.ipv4.tcp_fin_timeout=30
        生效,如下命令        
        /sbin/sysctl -p
        CLOSE_WAIT
       出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。
       代码需要判断socket,一旦读到0,断开连接,read返回负,检查一下errno,如果不是AGAIN,就断开连接。
    展开全文
  • WaitUntil

    千次阅读 2019-04-24 20:56:39
    public static Action callback; public static IEnumerator WaitIns { get { return WaitInstance();...private static WaitUntil wait = new WaitUntil(MonoBaseObserveManageListener); [Obsolete] public stat...

    public static Action callback;
    public static IEnumerator WaitIns { get { return WaitInstance(); } }
    private static WaitUntil wait = new WaitUntil(MonoBaseObserveManageListener);
    [Obsolete]
    public static void AddWaitInstanceCallback(Action act)
    {
    callback += act;
    }
    [Obsolete]
    public static void RemoveWaitInstanceCallback(Action act)
    {
    callback -= act;
    }
    public static IEnumerator WaitInstance()
    {
    yield return wait;
    if (callback != null)
    callback();
    }

        private static bool MonoBaseObserveManageListener()
        {
            return MonoBaseObserveManager.Instance != null;
        }
    
    展开全文
  • wait3,wait4 用法

    万次阅读 2016-01-24 20:01:23
    wait3和wait4的用法

    本文属于互联网文章集合。

    在阅读redis代码的时候看到的一些新知识,新用法,wait3的用法。

    redis的用法。

     int statloc;
            pid_t pid;
    
            if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
                int exitcode = WEXITSTATUS(statloc);
                int bysignal = 0;
    
                if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);
    

    所以,我们要了解一下wait3,wait4


    wait3, wait4 - wait for process to change state, BSD style
    
    Synopsis
    
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #include <sys/wait.h>
    
    pid_t wait3(int *status, int options,
                struct rusage *rusage);
    
    pid_t wait4(pid_t pid, int *status, int options,
                struct rusage *rusage);

    以下为转载

    http://blog.sina.com.cn/s/blog_65bda7120100kjxx.html

    wait3和wait4函数除了可以获取子进程状态转变信息外,还可以获得子进程的资源使用信息。

        pid_t wait3 ( int *status, int option, struct rusage *ru );

        pid_t wait4 ( pid_t pid, int *status, int option, struct rusage *ru );

        option的可选值有:WNOHANG、WCONTINUED、WUNTRACED。

        wait3等待所有的子进程;wait4可以像waitpid一样指定要等待的子进程:pid>0表示子进程ID;pid=0表示当前进程组中的子进程;pid=-1表示等待所有子进程;pid<-1表示进程组ID为pid绝对值的子进程。

        通过ru指针可以返回子进程的资源使用情况。

        struct rusage {
                    struct timeval ru_utime;
                    struct timeval ru_stime;
                    long   ru_maxrss;       
                    long   ru_ixrss;        
                    long   ru_idrss;        
                    long   ru_isrss;        
                    long   ru_minflt;       
                    long   ru_majflt;       
                    long   ru_nswap;        
                    long   ru_inblock;      

                    long   ru_oublock;      
                    long   ru_msgsnd;       
                    long   ru_msgrcv;       
                    long   ru_nsignals;     
                    long   ru_nvcsw;        
                    long   ru_nivcsw;       
                };

        也可以通过getrusage函数获取进程资源使用情况。

        int getrusage ( int who, struct rusage *ru );

        who可取RUSAGE_SELF、RUSAGE_CHILDREN,分别获取当前进程的资源使用情况和所有已终止且被父进程获取其终止状态的所有子进程的资源使用总情况。


    下面是一些宏的用法。

    If the exit status value (*note Program Termination::) of the child
    process is zero, then the status value reported by `waitpid' or `wait'
    is also zero. You can test for other kinds of information encoded in
    the returned status value using the following macros. These macros are
    defined in the header file `sys/wait.h'.

    -- Macro: int WIFEXITED (int STATUS)
         This macro returns a nonzero value if the child process terminated
         normally with `exit' or `_exit'.

    -- Macro: int WEXITSTATUS (int STATUS)
         If `WIFEXITED' is true of STATUS, this macro returns the low-order
         8 bits of the exit status value from the child process. *Note
         Exit Status::.

    -- Macro: int WIFSIGNALED (int STATUS)
         This macro returns a nonzero value if the child process terminated
         because it received a signal that was not handled. *Note Signal
         Handling::.

    子进程的结束状态返回后存于status,底下有几个宏可判别结束情况
    WIFEXITED(status)如果子进程正常结束则为非0值。
    WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。
    WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真
    WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。
    WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。
    WSTOPSIG(status)取得引发子进程暂停的信号代码,



    If the exit status value (*note Program Termination::) of the child
    process is zero, then the status value reported by `waitpid' or `wait'
    is also zero. You can test for other kinds of information encoded in
    the returned status value using the following macros. These macros are
    defined in the header file `sys/wait.h'.

    -- Macro: int WIFEXITED (int STATUS)
         This macro returns a nonzero value if the child process terminated
         normally with `exit' or `_exit'.

    -- Macro: int WEXITSTATUS (int STATUS)
         If `WIFEXITED' is true of STATUS, this macro returns the low-order
         8 bits of the exit status value from the child process. *Note
         Exit Status::.

    -- Macro: int WIFSIGNALED (int STATUS)
         This macro returns a nonzero value if the child process terminated
         because it received a signal that was not handled. *Note Signal
         Handling::.

    子进程的结束状态返回后存于status,底下有几个宏可判别结束情况
    WIFEXITED(status)如果子进程正常结束则为非0值。
    WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。
    WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真
    WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。
    WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。
    WSTOPSIG(status)取得引发子进程暂停的信号代码,

    展开全文
  • 一般IO复用是使用 one loop per thread 的模型, 一般wait都是可读事件,监听可写需实时添加,如果遇到wait线程在等待可读事件,并一直阻塞下去, 却有一个线程想添加监听可写事件,这时需要唤醒wait,并添加可写...
  • wait3和wait4 Functions

    2016-02-29 20:44:10
    提供了与wait,waitpid,waitid函数唯一不能提供的特性:增加了额外的参数,用于存放中止进程的所有资源的汇总和其所有的子进程wait3, wait4 - wait for process to change state, BSD style#include #include #...
  • wait方法

    千次阅读 2019-03-24 10:33:14
    一.概念、原理、区别 Java中的多线程是一种抢占式的机制而不是分时机制。线程主要有以下几种状态:可运行,运行,阻塞,等待,等待超时,死亡。抢占式机制指的是有多个线程处于可运行状态,... Object的方法:wait...
  • Verilog wait语句

    万次阅读 2019-01-20 11:04:56
    wait语句 wait语句是一种不可综合的电平触发事件控制语句,有如下两种形式:   wait(条件表达式) 语句/语句块; wait(条件表达式); 对于第一种形式,语句块可以是串行块(begin…end)或并行块(fork…join)。当...
  • TIME_WAIT和CLOSE_WAIT的区别

    千次阅读 2019-04-18 14:35:25
    系统上线之后,通过如下语句查看服务器时,发现有不少TIME_WAIT和CLOSE_WAIT。 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' TIME_WAIT 297 ESTABLISHED 53 CLOSE_WAIT 5 解释 TIME_...
  • sleep和wait的区别

    万次阅读 多人点赞 2019-05-08 23:24:46
    wait()方法,则是属于Object类中的。 sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。 在调用sleep()方法的过程中,线程不会...
  • TCP四次挥手之FIN_WAIT_2和CLOSE_WAIT,TIME_WAIT以及LAST_ACK的细节
  • 进程调用 exit() 退出执行... wait4() 系统调用由 linux 内核实现,linux 系统通常提供了 wait()、waitpid()、wait3()、wait4() 这四个函数,四个函数的参数不同,语义也有细微的差别,但是都返回关于终止进程的状态...
  • wait函数详解

    万次阅读 2018-02-26 23:55:13
    进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一...
  • TIMEWAIT状态

    千次阅读 2018-12-11 09:17:12
    TIMEWAIT是友好的 修改内核参数/proc/sys/net/ipv4/tcp_tw_recycle来快速回收被关闭的socket,使得TCP连接根本就不进入TIME_WAIT状态 客户端在接收到服务器发送的FIN段后,没有立即进入CLOSED状态,而是进入TIME_...
  • 文章目录存在close_wait的原因和解决办法存在FIN_WAIT2的原因和解决办法存在TIME_WAIT的原因和解决办法处理这类问题的实用命令 存在close_wait的原因和解决办法 close_wait这个状态存在于服务端,当服务端发送FIN...
  • 先给出四次挥手过程中C/S的状态变化示意图。有了图理解起来就容易许多。...TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。 CLOSE_WAIT状态的生成原因 首先我们知道,如果我们的服务器程序APACHE处于CLOS
  • COMMIT WORK AND WAIT 是在WAIT什么

    千次阅读 2016-10-09 15:42:48
    COMMIT WORK AND WAIT 是在WAIT什么 wait 还是不wait,这是个问题。 这是同步更新还是异步更新的问题;如果是只commit work,是异步更新,触发注册在当前SAP LUW中所有数据更新动作,数据更新动作由...
  • wait线程阻塞

    2018-09-16 19:12:40
    介绍 线程阻塞通常是指一个线程在执行过程中由于某种原因从运行状态转为暂停状态的过程,线程阻塞会...首先我们先看wait方法,wait方法总共有三个重载方法,分别是 wait() wait(long timeout) wait(long timeout...
  • wait和waitpid详解

    千次阅读 2020-11-03 22:58:17
    wait和waitpid详解 1、wait 头文件 #include <sys/types.h> #include <sys/wait.h> 函数原型 pid_t wait(int *status); 参数 status:代表返回状态,成功调用返回子进程pid,如果没有子 进程调用...
  • 下面接着《详解TCPIP断开连接后的Time-wait状态》一文的内容,我们讨论下socket在断开连接中的另外三种状态FIN_WAIT1、FIN_WAIT2状态和CLOSE_WAIT状态。 首先启动socket服务端,然后用客户端进行连接,用netstat –...
  • 服务器 TIME_WAIT和CLOSE_WAIT

    千次阅读 2016-11-26 16:10:50
    1、查询服务器端口占用情况 命令行: netstat -ano 》D:\YSH.txtESTABLISHED:表示...time_wait以及close_wait过多可能导致系统端口用尽的情况,无法正常建立TCP 连接。tcp 状态变化图如下:2、(通过优化系统内核参
  • Golang sync.WaitGroup

    千次阅读 2020-08-04 11:18:11
    在 sync.WaitGroup(等待组)类型中,每个 sync.WaitGroup 值在内部维护着一个计数,此计数的初始默认值为零。 等待组有下面几个方法可用,如下所示。 func (wg *WaitGroup) Add(delta int): 等待组的计数器 +1 ...
  • python wait方法 Python Condition.wait()方法 (Python Condition.wait() Method) wait() is an inbuilt method of the Condition class of the threading module in Python. wait()是Python中线程模块的Condition...
  • Java wait() notify()方法使用实例讲解

    万次阅读 多人点赞 2015-04-08 14:54:37
    1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。  2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁,或者叫管程)  3)调用某个对象的...
  • 今天有位同学过来问我下面代码中那个super.wait()是什么意思? public synchronized void waitAvailable() { try { if (num == "wait") super.wait(); } catch (InterruptedException ex) { } } 那...
  • 1、sleep()函数在Thread类中,wait()函数属于Object类,源码如下: sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。 2...
  • 关于 time wait

    千次阅读 2018-07-17 12:43:31
    网上有很多关于 time wait 的问题和修改方案,究竟什么是 time wait?作用是什么?会造成什么问题?如何解决?我们接下来一点一点看一下。 一,time wait 是什么? timewait 状态是 TCP 链接的主动关闭方会有的...
  • 服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

    千次阅读 热门讨论 2017-11-28 16:09:14
    服务器TIME_WAIT和CLOSE_WAIT详解和解决办法
  • 休眠 所谓休眠就是让出CPU 然后并不返回 wait_event_interruptible(wq, condition) condition = 0 ///休眠 ...wait_event_interruptible()和wait_up_interruptible() wait_event_interruptible...
  • 一文详解wait与notify

    万次阅读 2020-05-28 14:49:29
    1)使用wait/notify实现线程间的通信。 2)生产者/消费者模式的实现。 3)方法join的使用。 4)ThreadLocal类的使用。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 142,514
精华内容 57,005
关键字:

wait