【引言】

说到TCP协议,相信大家都比较熟悉了,对于TCP协议总能说个一二三来,但是TCP协议又是一个非常复杂的协议,其中有不少细节点让人头疼。本文就是来说说这些头疼点的,浅谈一些TCP的疑难杂症。那么从哪说起呢?当然是从三次握手和四次挥手说起啦,可能大家都知道TCP是三次交互完成连接的建立,四次交互来断开一个连接,那为什么是三次握手和四次挥手呢?反过来不行吗?

疑症一:TCP的三次握手、四次挥手

下面两图大家再熟悉不过了,TCP的三次握手和四次挥手见下面左边的”TCP建立连接”、”TCP数据传送”、”TCP断开连接”时序图和右边的”TCP协议状态机”

图片描述

TCP三次握手、四次挥手时序图

图片描述

TCP协议状态机

要弄清TCP建立连接需要几次交互才行,我们需要弄清建立连接进行初始化的目标是什么。TCP进行握手初始化一个连接的目标是:分配资源、初始化序列号(通知Peer对端我的初始序列号是多少),知道初始化连接的目标,那么要达成这个目标的过程就简单了,握手过程可以简化为下面的四次交互:

(1) Client端首先发送一个SYN包告诉Server端我的初始序列号是X;

(2) Server端收到SYN包后回复给Client一个ACK确认包,告诉Client说我收到了;

(3) 接着Server端也需要告诉Client端自己的初始序列号,于是Server也发送一个SYN包告诉Client我的初始序列号是Y;

(4) Client收到后,回复Server一个ACK确认包说我知道了。

整个过程4次交互即可完成初始化,但是,细心的同学会发现两个问题:[1] Server发送SYN包是作为发起连接的SYN包,还是作为响应发起者的SYN包?怎么区分?比较容易引起混淆 ;[2] Server的ACK确认包和接下来的SYN包可以合成一个SYN ACK包一起发送的,没必要分别单独发送,这样省了一次交互同时也解决了问题[1]。 这样TCP建立一个连接,三次握手在进行最少次交互的情况下完成了Peer两端的资源分配和初始化序列号的交换。

大部分情况下建立连接需要三次握手,也不一定都是三次,有可能出现四次握手来建立连接的。如下图,当Peer两端同时发起SYN来建立连接时,就出现了四次握手来建立连接(对于有些TCP/IP的实现,可能不支持这种同时打开的情况)。

图片描述

在三次握手过程中,细心的同学可能会有以下疑问:

  • 初始化序列号X、Y是可以是写死固定的吗,为什么不能?
  • 假如Client发送一个SYN包给Server后就挂了或是不管了,这个时候这个连接处于什么状态?会超时吗?为什么?

TCP进行断开连接的目标是:回收资源、终止数据传输。由于TCP是全双工的,需要Peer两端分别各自拆除自己通向Peer对端方向的通信信道。这样需要四次挥手来分别拆除通信信道,就比较清晰明了了。

(1) Client发送一个FIN包来告诉Server我已经没数据需要发给Server了;

(2) Server收到后回复一个ACK确认包说我知道了;

(3) 然后Server在自己也没数据发送给Client后,Server也发送一个FIN包给Client告诉Client我也已经没数据发给Client了;

(4) Client收到后,就会回复一个ACK确认包说我知道了。

到此,四次挥手,这个TCP连接就可以完全拆除了。在四次挥手的过程中,细心的同学可能会有以下疑问:

  • Client和Server同时发起断开连接的FIN包会怎么样呢,TCP状态是怎么转移的?
  • 左侧图中的四次挥手过程中,Server端的ACK确认包能不能和接下来的FIN包合并成一个包,这样四次挥手就变成三次挥手了。
  • 四次挥手过程中,首先断开连接的一端,在回复最后一个ACK后,为什么要进行`TIME_
  • 呢(超时设置是 2*MSL,RFC793定义了MSL为2分钟,Linux设置成了30s),在TIME_WAIT的时候又不能释放资源,白白让资源占用那么长时间,能否省去TIME_WAIT`,为什么?

疑症二:TCP连接的初始化序列号能否固定

如果初始化序列号(缩写为ISN:Inital Sequence Number)可以固定,我们来看看会出现什么问题。假设ISN固定是1,Client和Server建立好一条TCP连接后,Client连续给Server发了10个包,这10个包不知怎么被链路上的路由器缓存了(路由器会毫无先兆地缓存或者丢弃任何的数据包),这个时候碰巧Client挂掉了,然后Client用同样的端口号重新连上Server,Client又连续给Server发了几个包,假设这个时候Client的序列号变成了5。接着,之前被路由器缓存的10个数据包全部被路由到Server端了,Server给Client回复确认号10,这个时候,Client整个都不好了,这是什么情况?我的序列号才到5,你怎么给我的确认号是10了,整个都乱了。

RFC793中,建议ISN和一个假的时钟绑在一起,这个时钟会在每4微秒对ISN做加一操作,直到超过2^32,又从0开始,这需要4小时才会产生ISN的回绕问题,这几乎可以保证每个新连接的ISN不会和旧连接的ISN产生冲突。这种递增方式的ISN,很容易让攻击者猜测到TCP连接的ISN,现在的实现大多是在一个基准值的基础上随机进行的。

疑症三:初始化连接的SYN超时问题

Client发送SYN包给Server后挂了,Server回给Client的SYN-ACK一直没收到Client的ACK确认,此时这个连接既没建立起来,也不能算失败。这就需要一个超时时间让Server将这个连接断开,否则这个连接就会一直占用Server的SYN连接队列中的一个位置,大量这样的连接就会将Server的SYN连接队列耗尽,让正常的连接无法得到处理。目前,Linux下默认会进行5次重发SYN-ACK包,重试的间隔时间从1s开始,下次的重试间隔时间是前一次的双倍,5次的重试时间间隔为1s,2s,4s,8s,16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才会断开这个连接。由于,SYN超时需要63秒,那么就给攻击者一个攻击服务器的机会,攻击者在短时间内发送大量的SYN包给Server(俗称SYN flood攻击),用于耗尽Server的SYN队列。对于应对SYN过多的问题,Linux提供了几个TCP参数:tcp_syncookiestcp_synack_retriestcp_max_syn_backlogtcp_abort_on_overflow来调整应对。

疑症四:TCP的Peer两端同时断开连接

由上面的”TCP协议状态机 “图可以看出,TCP的Peer端在收到对端的FIN包前发出了FIN包,那么该Peer的状态就变成了FIN_WAIT1,Peer在FIN_WAIT1状态下收到对端Peer对自己FIN包的ACK包的话,那么Peer状态就变成FIN_WAIT2,Peer在FIN_WAIT2下收到对端Peer的FIN包,在确认已经收到了对端Peer全部的Data数据包后,就响应一个ACK给对端Peer,然后自己进入TIME_WAIT状态;但是如果Peer在FIN_WAIT1状态下首先收到对端Peer的FIN包的话,那么该Peer在确认已经收到了对端Peer全部的Data数据包后,就响应一个ACK给对端Peer,然后自己进入CLOSEING状态,Peer在CLOSEING状态下收到自己FIN包的ACK包的话,那么就进入TIMEWAIT状态。于是,TCP的Peer两端同时发起FIN包进行断开连接,那么两端Peer可能出现完全一样的状态转移FIN_WAIT1---->CLOSEING----->TIME_WAIT,Client和Server也就会最后同时进入TIME_WAIT状态。同时关闭连接的状态转移如下图所示:

图片描述

疑症五:四次挥手能否变成三次挥手?

答案是可能的。TCP是全双工通信,Cliet在自己已经不会再有新的数据要发送给Server后,可以发送FIN信号告知Server,这边已经终止Client到对端Server的数据传输。但是,这个时候对端Server可以继续往Client这边发送数据包。于是,两端数据传输的终止在时序上独立并且可能会相隔比较长的时间,这个时候就必须最少需要2+2=4次挥手来完全终止这个连接。但是,如果Server在收到Client的FIN包后,再也没数据需要发送给Client了,那么对Client的ACK包和Server自己的FIN包就可以合并成一个包发送过去,这样四次挥手就可以变成三次了(似乎Linux协议栈就是这样实现的)。

疑症六:TCP的头号疼症TIME_WAIT状态

要说明TIME_WAIT的问题,需要解答以下几个问题:

1. Peer两端,哪一端会进入TIME_WAIT,为什么?

相信大家都知道,TCP主动关闭连接的那一方会最后进入TIME_WAIT。那么怎么界定主动关闭方?是否主动关闭是由FIN包的先后决定的,就是在自己没收到对端Peer的FIN包之前自己发出了FIN包,那么自己就是主动关闭连接的那一方。对于疑症四中描述的情况,那么Peer两边都是主动关闭的一方,两边都会进入TIME_WAIT。为什么是主动关闭的一方进行TIME_WAIT呢,被动关闭的进入TIME_WAIT可以吗?我们来看看TCP四次挥手可以简单分为下面三个过程

过程一:主动关闭方发送FIN; 
过程二:被动关闭方收到主动关闭方的FIN后发送该FIN的ACK,被动关闭方发送FIN; 
过程三:主动关闭方收到被动关闭方的FIN后发送该FIN的ACK,被动关闭方等待自己FIN的ACK

问题就在过程三中,据TCP协议规范,不对ACK进行ACK,如果主动关闭方不进入TIME_WAIT,那么主动关闭方在发送完ACK就走了的话,如果最后发送的ACK在路由过程中丢掉了,最后没能到被动关闭方,这个时候被动关闭方没收到自己FIN的ACK就不能关闭连接,接着被动关闭方会超时重发FIN包,但是这个时候已经没有对端会给该FIN回ACK,被动关闭方就无法正常关闭连接了,所以主动关闭方需要进入TIME_WAIT以便能够重发丢掉的被动关闭方FIN的ACK。

2. TIME_WAIT状态是用来解决或避免什么问题呢?

TIME_WAIT主要是用来解决以下几个问题:

(1) 上面解释为什么主动关闭方需要进入TIME_WAIT状态中提到的:主动关闭方需要进入TIME_WAIT以便能够重发丢掉的被动关闭方FIN包的ACK。如果主动关闭方不进入TIME_WAIT,那么在主动关闭方对被动关闭方FIN包的ACK丢失了的时候,被动关闭方由于没收到自己FIN的ACK,会进行重传FIN包,这个FIN包到主动关闭方后,由于这个连接已经不存在于主动关闭方了,这个时候主动关闭方无法识别这个FIN包,协议栈会认为对方疯了,都还没建立连接你给我来个FIN包?于是回复一个RST包给被动关闭方,被动关闭方就会收到一个错误(我们见的比较多的:connectreset by peer。这里顺便说下Broken pipe,在收到RST包的时候,还往这个连接写数据,就会收到Broken pipe错误了),原本应该正常关闭的连接,给我来个错误,很难让人接受。

(2) 防止已经断开的连接1中在链路中残留的FIN包终止掉新的连接2[重用了连接1的所有5元素(源IP,目的IP,TCP,源端口,目的端口)],这个概率比较低,因为涉及到一个匹配问题,迟到的FIN分段的序列号必须落在连接2一方的期望序列号范围之内,虽然概率低,但是确实可能发生,因为初始序列号都是随机产生的,并且这个序列号是32位的,会回绕。

(3) 防止链路上已经关闭的连接的残余数据包(a lost duplicate packet or a wandering duplicate packet)干扰正常的数据包,造成数据流不正常。这个问题和(2)类似。

3. TIME_WAIT会带来哪些问题?

TIME_WAIT带来的问题主要是源于:一个连接进入TIME_WAIT状态后需要等待2*MSL(一般是1到4分钟)那么长的时间才能断开连接释放连接占用的资源,会造成以下问题:

(1) 作为服务器,短时间内关闭了大量的Client连接,就会造成服务器上出现大量的TIME_WAIT连接,占据大量的tuple,严重消耗着服务器的资源; 
(2) 作为客户端,短时间内大量的短连接,会大量消耗Client机器的端口,毕竟端口只有65535个,端口被耗尽了,后续就无法再发起新的连接了。

(由于上面两个问题,作为客户端需要连本机的一个服务的时候,首选UNIX域套接字而不是TCP)

TIME_WAIT很令人头疼,很多问题是由TIME_WAIT造成的,但TIME_WAIT又不是多余的,所以不能简单将TIME_WAIT去掉,那么如何来解决或缓解TIME_WAIT问题?可以进行TIME_WAIT的快速回收和重用来缓解TIME_WAIT的问题。是否有一些清掉TIME_WAIT的技巧?

4. TIME_WAIT的快速回收和重用

(1) TIME_WAIT快速回收

Linux下开启TIME_WAIT快速回收需要同时打开tcp_tw_recycletcp_timestamps(默认打开)两选项。Linux下快速回收的时间为3.5*RTO(RetransmissionTimeout),而一个RTO时间为200ms至120s。开启快速回收TIME_WAIT,可能会带来问题一中说的三点危险,为了避免这些危险,要求同时满足以下三种情况的新连接被拒绝掉。

[1] 来自同一个对端Peer的TCP包携带了时间戳

[2] 之前同一台peer机器(仅仅识别IP地址,因为连接被快速释放了,没了端口信息)的某个TCP数据在MSL秒之内到过本Server

[3] Peer机器新连接的时间戳小于Peer机器上次TCP到来时的时间戳,且差值大于重放窗口戳(TCP_PAWS_WINDOW

初看起来正常的数据包同时满足上面3条几乎不可能,因为机器的时间戳不可能倒流的,出现上述的3点均满足时,一定是老的重复数据包又回来了,丢弃老的SYN包是正常的。到此,似乎启用快速回收就能很大程度缓解TIME_WAIT带来的问题。但是,这里忽略了一个东西就是NAT——在一个NAT后面的所有Peer机器在Server看来都是一个机器,NAT后面的那么多Peer机器的系统时间戳很可能不一致,有些快,有些慢。这样,在Server关闭了与系统时间戳快的Client的连接后,在这个连接进入快速回收的时候,同一NAT后面的系统时间戳慢的Client向Server发起连接,这就很有可能同时满足上面的三种情况,造成该连接被Server拒绝掉。所以,在是否开启tcp_tw_recycle需要慎重考虑。

(2) TIME_WAIT重用

Linux上比较完美地实现了TIME_WAIT重用问题。只要满足下面两点中的一点,一个TW状态的四元组(即一个socket连接)可以重新被新到来的SYN连接使用

[1] 新连接SYN告知的初始序列号比TIME_WAIT老连接的末序列号大

[2] 如果开启了tcp_timestamps,并且新到来的连接的时间戳比老连接的时间戳大

要同时开启tcp_tw_reuse选项和tcp_timestamps选项才可以开启TIME_WAIT重用,还有一个条件是:重用TIME_WAIT的条件是收到最后一个包后超过1s。细心的同学可能发现TIME_WAIT重用对Server端来说并没解决大量TIME_WAIT造成的资源消耗的问题,因为不管TIME_WAIT连接是否被重用,它依旧占用着系统资源。即便如此,TIME_WAIT重用还是有些用处的,它解决了整机范围拒绝接入的问题,虽然一般一个单独的Client是不可能在MSL内用同一个端口连接同一个服务的,但是如果Client做了bind端口那就是同一个端口了。时间戳重用TIME_WAIT连接机制的前提是IP地址唯一性,得出新请求发起自同一台机器,但是如果是NAT环境下就不能这样保证了,于是在NAT环境下,TIME_WAIT重用还是有风险的。

有些同学可能会混淆tcp_tw_reuseSO_REUSEADDR选项,认为是相关的东西,其实它们是两个完全不同的东西,可以说半毛钱关系都没。tcp_tw_reuse是内核选项,而SO_REUSEADDR用户态的选项,使用SO_REUSEADDR是告诉内核,如果端口忙,但TCP状态位于TIME_WAIT,可以重用端口。如果端口忙,而TCP状态位于其它状态,重用端口时依旧得到一个错误信息,指明Addressalready in use。如果你的服务程序停止后想立即重启,而新套接字依旧使用同一端口,此时SO_REUSEADDR选项非常有用。但是,使用这个选项就会有(问题二)中说的三点危险,虽然发生的概率不大。

5. 清掉TIME_WAIT的奇技怪巧

可以用下面两种方式控制服务器的TIME_WAIT数量:

(1) 修改tcp_max_tw_buckets

tcp_max_tw_buckets控制并发的TIME_WAIT数量,默认值是180000。如果超过默认值,内核会把多的TIME_WAIT连接清掉,然后在日志里打一个警告。官网文档说这个选项只是为了阻止一些简单的DoS攻击,平常不要人为降低它。

(2) 利用RST包从外部清掉TIME_WAIT链接

根据TCP规范,收到任何发送到未侦听端口、已经关闭的连接的数据包、连接处于任何非同步状态(LISTEN, SYS-SENT,SYN-RECEIVED)并且收到的包的ACK在窗口外,或者安全层不匹配,都要回执以RST响应(而收到滑动窗口外的序列号的数据包,都要丢弃这个数据包,并回复一个ACK包),内核收到RST将会产生一个错误并终止该连接。我们可以利用RST包来终止掉处于TIME_WAIT状态的连接,其实这就是所谓的RST攻击了。为了描述方便:假设Client和Server有个连接Connect1,Server主动关闭连接并进入了TIME_WAIT状态,我们来描述一下怎么从外部使得Server处于TIME_WAIT状态的连接Connect1提前终止掉。要实现这个RST攻击,首先我们要知道Client在Connect1中的端口port1(一般这个端口是随机的,比较难猜到,这也是RST攻击较难的一个点),利用IP_TRANSPARENT这个socket选项,它可以bind不属于本地的地址,因此可以从任意机器绑定Client地址以及端口port1,然后向Server发起一个连接,Server收到了窗口外的包于是响应一个ACK,这个ACK包会路由到Client处,这个时候可能99%的Client已经释放连接Connect1了,这个时候Client收到这个ACK包,会发送一个RST包,Server收到RST包然后就释放连接Connect1提前终止TIME_WAIT状态。提前终止TIME_WAIT状态是可能会带来(问题二)中说的三点危害,具体的危害情况可以看下RFC1337。RFC1337中建议,不要用RST过早的结束TIME_WAIT状态。

至此,上面的疑症都解析完毕,然而细心的同学会有下面的疑问:

  • TCP的可靠传输是确认号来实现的,那么TCP的确认机制是怎样的呢?是收到一个包就马上确认,还是可以稍等一下再确认?
  • 假如发送一个包,一直都没收到确认呢?什么时候重传?超时机制是怎样的?
  • TCP两端Peer的处理能力不对等时,比如发送方处理能力很强,接收方处理能力很弱,这样发送方是否能够不管接收方死活狂发数据?如果不能,流量控制机制是怎样的?
  • TCP是端到端的协议,也就是TCP对端Peer只看到对方,看不到网络上的其他点,那么TCP的两端如何对网络情况做出反映?发生拥塞时,拥塞控制机制是怎样的?

疑症七:TCP的延迟确认机制

按照TCP协议,确认机制是累积的,也就是确认号X确认指示的是所有X之前但不包括X的数据已经收到了。确认号(ACK)本身就是不含数据的分段,因此大量的确认号消耗了大量的带宽,虽然大多数情况下,ACK还是可以和数据一起捎带传输,但是如果没有捎带传输,那么就只能单独回来一个ACK,如果这样的分段太多,网络的利用率就会下降。为缓解这个问题,RFC建议了一种延迟的ACK,也就是说,ACK在收到数据后并不马上回复,而是延迟一段可以接受的时间,延迟一段时间的目的是看能不能和接收方要发给发送方的数据一起回去,因为TCP协议头中总是包含确认号的,如果能的话,就将数据一起捎带回去,这样网络利用率就提高了。延迟ACK就算没有数据捎带,那么如果收到了按序的两个包,那么只要对第二包做确认即可,这样也能省去一个ACK消耗。由于TCP协议不对ACK进行ACK,RFC建议最多等待2个包的积累确认,这样能够及时通知对端Peer我这边的接收情况。Linux实现中,有延迟ACK和快速ACK,并根据当前的包的收发情况来在这两种ACK中切换。一般情况下,ACK并不会对网络性能有太大的影响,延迟ACK能减少发送的分段从而节省带宽,而快速ACK能及时通知发送方丢包,避免滑动窗口停等,提升吞吐率。关于ACK分段,有个细节需要说明一下,ACK的确认号,是确认按序收到的最后一个字节序,对于乱序到来的TCP分段,接收端会回复相同的ACK分段,只确认按序到达的最后一个TCP分段。TCP连接的延迟确认时间一般初始化为最小值40ms,随后根据连接的重传超时时间(RTO)、上次收到数据包与本次接收数据包的时间间隔等参数进行不断调整。

疑症八:TCP的重传机制以及重传的超时计算

1. TCP的重传超时计算

TCP交互过程中,如果发送的包一直没收到ACK确认,是要一直等下去吗?显然不能一直等(如果发送的包在路由过程中丢失了,对端都没收到又如何给你发送确认呢?),这样协议将不可用,既然不能一直等下去,那么该等多久?等太长时间的话,数据包都丢了很久了才重发,没有效率,性能差;等太短时间的话,可能ACK还在路上快到了,这时候却重传了,造成浪费,同时过多的重传会造成网络拥塞,进一步加剧数据的丢失。也是,我们不能去猜测一个重传超时时间,应该是通过一个算法去计算,并且这个超时时间应该是随着网络状况在变化的。为了使我们的重传机制更高效,如果我们能够比较准确知道在当前网络状况下,一个数据包从发出去到回来的时间RTT——RoundTrip Time,那么根据这个RTT我们就可以方便设置TimeOut——RTO(Retransmission TimeOut)了。

为了计算这个RTO,RFC793中定义了一个经典算法,算法如下:

[1] 首先采样计算RTT值

[2] 然后计算平滑的RTT,称为Smoothed Round Trip Time (SRTT),SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)

[3] RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]

其中:UBOUND是RTO值的上限,例如:可以定义为1分钟;LBOUND是RTO值的下限,例如,可以定义为1秒。ALPHA is a smoothing factor (e.g., .8 to .9), and BETA is a delay variance factor (e.g., 1.3 to 2.0). 然而这个算法有个缺点就是:在算RTT样本的时候,是用第一次发数据的时间和ACK回来的时间做RTT样本值,还是用重传的时间和ACK回来的时间做RTT样本值?不管怎么选择,总会造成会要么把RTT算过长了,要么把RTT算过短了。如下图:(a)就计算过长了,而(b)就是计算过短了。

图片描述

针对上面经典算法的缺陷,提出Karn/Partridge Algorithm对经典算法进行了改进(算法大特点是——忽略重传,不把重传的RTT做采样),但是这个算法有问题:如果在某一时间,网络闪动,突然变慢了,产生了比较大的延时,这个延时导致要重转所有的包(因为之前的RTO很小),于是,因为重转不算,所以,RTO就不会被更新,这是一个灾难。于是,为解决上面两个算法的问题,又有人推出来一个新的算法,这个算法叫Jacobson / Karels Algorithm(参看RFC6289),这个算法的核心是:除了考虑每两次测量值的偏差之外,其变化率也应该考虑在内,如果变化率过大,则通过以变化率为自变量的函数为主计算RTT(如果陡然增大,则取值为比较大的正数,如果陡然减小,则取值为比较小的负数,然后和平均值加权求和),反之如果变化率很小,则取测量平均值。

公式如下:(其中的DevRTT是Deviation RTT的意思)

SRTT = SRTT + α (RTT – SRTT) —— 计算平滑RTT

DevRTT = (1-β)DevRTT + β(|RTT-SRTT|) ——计算平滑RTT和真实的差距(加权移动平均)

RTO= µ * SRTT + ∂ *DevRTT —— 神一样的公式

(其中:在Linux下,α = 0.125,β = 0.25, μ = 1,∂ = 4 ——这就是算法中的“调得一手好参数”,nobody knows why, it just works…)最后的这个算法被用在今天的TCP协议中并工作非常好。

知道超时怎么计算后,很自然就想到定时器的设计问题。一个简单直观的方案就是为TCP中的每一个数据包维护一个定时器,在这个定时器到期前没收到确认,则进行重传。这种在设计理论上是很合理的,但是实现上,这种方案将会有非常多的定时器,会带来巨大内存开销和调度开销。既然不能每个包一个定时器,那么多少个包一个定时器比较好?这似乎比较难确定。可以换个思路,不要以包量来确定定时器,以连接来确定定时器是否会比较合理?目前,采取每一个TCP连接单一超时定时器的设计则成了一个默认的选择,并且RFC2988给出了每连接单一定时器的设计建议算法规则:

[1] 每一次一个包含数据的包被发送(包括重发),如果还没开启重传定时器,则开启它,使得它在RTO秒之后超时(按照当前的RTO值)。

[2] 当接收到一个ACK确认一个新的数据, 如果所有发出数据都被确认了,关闭重传定时器。

[3] 当接收到一个ACK确认一个新的数据,还有数据在传输,也就是还有没被确认的数据,重新启动重传定时器,使得它在RTO秒之后超时(按照当前的RTO值)。

[4] 当重传定时器超时后,依次做下列3件事情:

[4.1] 重传最早的尚未被TCP接收方ACK的数据包;

[4.2] 重新设置RTO为RTO*2(“还原定时器”),但是新RTO不应该超过RTO的上限(RTO有个上限值,这个上限值最少为60s);

[4.3] 重启重传定时器。

上面的建议算法体现了一个原则:没被确认的包必须可以超时,并且超时的时间不能太长,同时也不要过早重传。规则[1]、[3]、[4.3]共同说明了只要还有数据包没被确认,那么定时器一定会是开启着的(这样满足没被确认的包必须可以超时的原则)。规则[4.2]说明定时器的超时值是有上限的(满足超时的时间不能太长)。规则[3]说明,在一个ACK到来后重置定时器可以保护后发的数据不被过早重传。因为一个ACK到来了,说明后续的ACK很可能会依次到来,也就是说丢失的可能性并不大。规则[4.2]也是在一定程度上避免过早重传,因为,在出现定时器超时后,有可能是网络出现拥塞了,这个时候应该延长定时器,避免出现大量的重传进一步加剧网络拥塞。

2. TCP的重传机制

通过上面我们可以知道,TCP的重传是由超时触发的,这会引发一个重传选择问题,假设TCP发送端连续发了1、2、3、4、5、6、7、8、9、10共10包,其中4、6、8这3个包全丢失了,由于TCP的ACK是确认最后连续收到序号,这样发送端只能收到3号包的ACK,这样在TIME_OUT的时候,发送端就面临下面两个重传选择:

(1) 仅重传4号包 
(2) 重传3号后面所有的包,也就是重传4~10号包

上面两个选择的优缺点都比较明显。方案(1),优点:按需重传,能够最大程度节省带宽。缺点:重传会比较慢,因为重传4号包后,需要等下一个超时才会重传6号包。方案[2],优点:重传较快,数据能够较快交付给接收端。缺点:重传了很多不必要重传的包,浪费带宽,在出现丢包的时候,一般是网络拥塞,大量的重传又可能进一步加剧拥塞。

上面的问题是由于单纯以时间驱动来进行重传,都必须等待一个超时时间,不能快速对当前网络状况做出响应,如果加入以数据驱动呢?TCP引入了一种叫Fast Retransmit(快速重传)的算法,就是在连续收到3次相同确认号的ACK,就进行重传。这个算法基于这么一个假设:连续收到3个相同的ACK,那么说明当前的网络状况变好了,可以重传丢失的包了。

快速重传解决了timeout的问题,但是没解决重传一个还是重传多个的问题。出现难以决定是否重传多个包问题的根源在于,发送端不知道那些非连续序号的包已经到达接收端了,但是接收端是知道的,如果接收端告诉一下发送端不就可以解决这个问题吗?于是,RFC2018提出了Selective Acknowledgment(SACK,选择确认)机制,SACK是TCP的扩展选项,包括(1) SACK允许选项(Kind=4,Length=2,选项只允许在有SYN标志的TCP包中),(2) SACK信息选项(Kind=5,Length)。一个SACK的例子如下图,红框说明:接收端收到了0-5500,8000-8500,7000-7500,6000-6500的数据了,这样发送端就可以选择重传丢失的5500-6000,6500-7000,7500-8000的包。

图片描述

SACK依靠接收端的接收情况反馈,解决了重传风暴问题,这样够了吗?接收端能否反馈更多信息?显然是可以的,于是,RFC2883对SACK进行了扩展,提出了D-SACK,也就是利用第一块SACK数据中描述重复接收的不连续数据块的序列号参数,其他SACK数据则描述其他正常接收到的不连续数据。这样发送方利用第一块SACK,可以发现数据段被网络复制、错误重传、ACK丢失引起的重传、重传超时等异常的网络状况,使得发送端能更好调整自己的重传策略。D-SACK,有几个优点:

1)发送端可以判断出,是发包丢失了,还是接收端的ACK丢失了。(发送方,重传了一个包,发现并没有D-SACK那个包,那么就是发送的数据包丢了;否则就是接收端的ACK丢了,或者是发送的包延迟到达了);

2)发送端可以判断自己的RTO是不是有点小了,导致过早重传(如果收到比较多的D-SACK就该怀疑是RTO小了);

3)发送端可以判断自己的数据包是不是被复制了(如果明明没有重传该数据包,但是收到该数据包的D-SACK);

4)发送端可以判断目前网络上是不是出现了有些包被delay了,也就是出现先发的包却后到了。

疑症九:TCP的流量控制

我们知道TCP的窗口(Window)是一个16bit位字段,它代表的是窗口的字节容量,也就是TCP的标准窗口最大为2^16-1=65535个字节。另外在TCP的选项字段中还包含了一个TCP窗口扩大因子,option-kind为3,option-length为3个字节,option-data取值范围0-14。窗口扩大因子用来扩大TCP窗口,可把原来16bit的窗口,扩大为31bit。这个窗口是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。也就是,发送端是根据接收端通知的窗口大小来调整自己的发送速率的,以达到端到端的流量控制。尽管流量控制看起来简单明了,就是发送端根据接收端的限制来控制自己的发送就好了,但是细心的同学还是会有些疑问的:

(1) 发送端是怎么做到比较方便知道自己哪些包可以发,哪些包不能发?

(2) 如果接收端通知一个零窗口给发送端,这个时候发送端还能不能发送数据?如果不发数据,那一直等接收端口通知一个非0窗口吗,如果接收端一直不通知呢?

(3) 如果接收端处理能力很慢,这样接收端的窗口很快被填满,然后接收处理完几个字节,腾出几个字节的窗口后,通知发送端,这个时候发送端马上就发送几个字节给接收端吗?发送的话会不会太浪费了,就像一艘万吨油轮只装上几斤的油就开去目的地一样。对于发送端产生数据的能力很弱也一样,如果发送端慢吞吞产生几个字节的数据要发送,这个时候该不该立即发送?还是累积多点在发送?

1. 疑问(1)的解决

发送方要知道哪些可以发,哪些不可以发,一个简明的方案就是按照接收方的窗口通告,发送方维护一个一样大小的发送窗口就可以了,在窗口内的可以发,窗口外的不可以发,窗口在发送序列上不断后移,这就是TCP中的滑动窗口。如下图所示,对于TCP发送端其发送缓存内的数据都可以分为4类

[1] 已经发送并得到接收端ACK的; 
[2] 已经发送但还未收到接收端ACK的; 
[3] 未发送但允许发送的(接收方还有空间); 
[4] 未发送且不允许发送(接收方没空间了)。

其中,[2]和[3]两部分合起来称之为发送窗口。

图片描述

下面两图演示窗口的滑动情况,收到36的ACK后,窗口向后滑动5个byte。

图片描述

图片描述

2. 疑问(2)的解决

由问题(1)我们知道,发送端的发送窗口是由接收端控制的。下图,展示了一个发送端是怎么受接收端控制的。

图片描述

由上图我们知道,当接收端通知一个Zero窗口时,发送端的发送窗口也变成了0,也就是发送端不能发数据了。如果发送端一直等待,直到接收端通知一个非零窗口在发数据的话,这似乎太受限于接收端,如果接收端一直不通知新的窗口呢?显然发送端不能干等,起码有一个主动探测的机制。为解决0窗口的问题,TCP使用了Zero Window Probe技术,缩写为ZWP。发送端在窗口变成0后,会发ZWP的包给接收方,来探测目前接收端的窗口大小,一般这个值会设置成3次,每次大约30-60秒(不同的实现可能会不一样)。如果3次过后还是0的话,有的TCP实现就会发RST关掉这个连接。正如有人的地方就会有商机,那么有等待的地方就很有可能出现DDoS攻击点。攻击者可以在和Server建立好连接后,就向Server通告一个0窗口,然后Server端就只能等待进行ZWP,于是攻击者会并发大量这样的请求,把Server端的资源耗尽。

3. 疑问点(3)的解决

疑点(3)本质就是一个避免发送大量小包的问题。造成这个问题原因有二:1) 接收端一直在通知一个小的窗口;2) 发送端本身问题,一直在发送小包。这个问题,TCP中有个术语叫Silly Window Syndrome(糊涂窗口综合症)。解决这个问题的思路有两条:1) 接收端不通知小窗口;2) 发送端积累一下数据再发送。

思路1)是在接收端解决这个问题,David D Clark’s方案,如果收到的数据导致Window Size小于某个值,就ACK一个0窗口,这就阻止发送端再发数据过来。等到接收端处理了一些数据后Windows Size大于等于MSS,或者buffer有一半为空,就可以通告一个非0窗口。思路2)是在发送端解决这个问题,有个著名的Nagle’salgorithm——Nagle算法的规则。

[1]如果包长度达到MSS,则允许发送; 
[2]如果该包含有,FIN,则允许发送; 
[3]设置了TCP_NODELAY选项,则允许发送; 
[4]设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送; 
[5]上述条件都未满足,但发生了超时(一般为 200ms ),则立即发送。

规则[4]指出TCP连接上最多只能有一个未被确认的小数据包。从规则[4]可以看出Nagle算法并不禁止发送小的数据包(超时时间内),而是避免发送大量小的数据包。由于Nagle算法是依赖ACK的,如果ACK很快的话,也会出现一直发小包的情况,造成网络利用率低。TCP_CORK选项则是禁止发送小的数据包(超时时间内),设置该选项后,TCP会尽力把小数据包拼接成一个大的数据包(一个MTU)再发送出去,当然也不会一直等,发生了超时(一般为200ms),也立即发送。Nagle算法和CP_CORK选项提高了网络利用率,但增加延时。从规则[3]可以看出,设置TCP_NODELAY选项,就是完全禁用Nagle算法了。

这里要说一个小插曲,Nagle算法和延迟确认(Delayed Acknoledgement)一起,当出现(write-write-read)时会引发一个40ms的延时问题,这个问题在HTTP svr中体现得比较明显。场景如下:

客户端在请求下载HTTP svr中的一个小文件,一般情况下,HTTP svr都是先发送HTTP响应头部,然后再发送HTTP响应BODY(特别是比较多的实现在发送文件的实施采用的是sendfile系统调用,这就出现write-write-read模式了)。当发送头部的时候,由于头部较小,形成一个小的TCP包发送到客户端,这个时候开始发送body,由于body也较小,这样还是形成一个小的TCP数据包,根据Nagle算法,HTTP svr已经发送一个小的数据包了,在收到第一个小包的ACK后或等待200ms超时后才能再发小包,HTTPsvr不能发送这个body小TCP包;

客户端收到http响应头后,由于这是一个小的TCP包,于是客户端开启延迟确认,客户端在等待Svr的第二个包来再一起确认或等待一个超时(一般是40ms)再发送ACK包;这样就出现了你等我、然而我也在等你的死锁状态,于是出现最多的情况是客户端等待一个40ms的超时,然后发送ACK给HTTP svr,HTTP svr收到ACK包后再发送body部分。大家在测HTTP svr的时候就要留意这个问题了。

疑症十:TCP的拥塞控制

谈到拥塞控制,就要先谈谈拥塞的因素和本质。本质上,网络上拥塞的原因就是大家都想独享整个网络资源,对于TCP,端到端的流量控制必然会导致网络拥堵。这是因为TCP只看到对端的接收空间的大小,而无法知道链路上的容量,只要双方的处理能力很强,那么就可以以很大的速率发包,于是链路很快出现拥堵,进而引起大量的丢包,丢包又引发发送端的重传风暴,进一步加剧链路拥塞。另外一个拥塞的因素是链路上的转发节点,例如路由器,再好的路由器只要接入网络,总是会拉低网络的总带宽,如果在路由器节点上出现处理瓶颈,那么就很容易出现拥塞。由于TCP看不到网络的状况,那么拥塞控制是必须的并且需要采用试探性的方式来控制拥塞,于是拥塞控制要完成两个任务:(1)公平性;(2) 拥塞过后的恢复。

TCP发展到现在,拥塞控制方面的算法很多,其中Reno是目前应用最广泛且较为成熟的算法,下面着重介绍一下Reno算法(RFC5681)。介绍该算法前,首先介绍一个概念Duplicate Acknowledgment(冗余ACK、重复ACK)一般情况下一个ACK被称为冗余ACK,要同时满足下面几个条件(对于SACK,那么根据SACK的一些信息来进一步判断):

[1] 接收ACK的那端已经发出了一些还没被ACK的数据包 
[2] 该ACK没有捎带data 
[3] 该ACK的SYN和FIN位都是off的,也就是既不是SYN包的ACK也不是FIN包的ACK。 
[4] 该ACK的确认号等于接收ACK那端已经收到的ACK的最大确认号 
[5] 该ACK通知的窗口等接收该ACK的那端上一个收到的ACK的窗口

Reno算法包含4个部分:(1) 慢热启动算法–Slow Start;(2) 拥塞避免算法–Congestion Avoidance;(3) 快速重传-Fast Retransimit;(4) 快速恢复算法–Fast Recovery。TCP的拥塞控制主要原理依赖于一个拥塞窗口(cwnd)来控制,根据前面的讨论,我们知道有一个接收端通告的接收窗口(rwnd)用于流量控制;加上拥塞控制后,发送端真正的发送窗口=min(rwnd, cwnd)。关于cwnd的单位,在TCP中是以字节来做单位的,我们假设TCP每次传输都是按照MSS大小来发送数据,因此你可以认为cwnd按照数据包个数来做单位也可以理解,下面如果没有特别说明是字节,那么cwnd增加1也就是相当于字节数增加1个MSS大小。

1. 慢热启动算法–Slow Start:

慢启动体现了一个试探的过程,刚接入网络的时候先发包慢点,探测一下网络情况,然后在慢慢提速。不要一上来就拼命发包,这样很容易造成链路的拥堵,出现拥堵了在想到要降速来缓解拥堵这就有点成本高了,毕竟无数的先例告诫我们先污染后治理的成本是很高的。慢启动的算法如下(cwnd全称Congestion Window):

1)连接建好的开始先初始化cwnd = N,表明可以传N个MSS大小的数据 
2)每当收到一个ACK,++cwnd; 呈线性上升 
3)每当过了一个RTT,cwnd = cwnd*2; 呈指数让升 
4)还有一个慢启动门限ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入”拥塞避免算法-Congestion Avoidance”

根据RFC5681,如果MSS > 2190 bytes,则N = 2;如果MSS < 1095 bytes,则N = 4;如果2190 bytes >= MSS >= 1095 bytes,则N = 3。一篇Google的论文《An Argument for Increasing TCP’s Initial Congestion Window》建议把cwnd初始化成了10个MSS。Linux 3.0后采用了这篇论文的建议。

2. 拥塞避免算法–Congestion Avoidance:

慢启动的时候说过,cwnd是指数快速增长的,但是增长是有个门限ssthresh(一般来说大多数的实现ssthresh的值是65535字节)的,到达门限后进入拥塞避免阶段。在进入拥塞避免阶段后,cwnd值变化算法如下:

(1) 每收到一个ACK,调整cwnd为(cwnd + 1/cwnd)*MSS个字节 
(2) 每经过一个RTT的时长,cwnd增加1个MSS大小。

TCP是看不到网络的整体状况的,那么TCP认为网络拥塞的主要依据是它重传了报文段。前面我们说过TCP的重传分两种情况:

(1) 出现RTO超时,重传数据包。这种情况下,TCP就认为出现拥塞的可能性就很大,于是它反应非常’强烈’:

1) 调整门限ssthresh的值为当前cwnd值的1/2。 
2) reset自己的cwnd值为1 
3) 然后重新进入慢启动过程。

(2) 在RTO超时前,收到3个duplicate ACK进行重传数据包。这种情况下,收到3个冗余ACK后说明确实有中间的分段丢失,然而后面的分段确实到达了接收端,因为这样才会发送冗余ACK,这一般是路由器故障或者轻度拥塞或者其它不太严重的原因引起的,因此此时拥塞窗口缩小的幅度就不能太大,此时进入快速重传。

3. 快速重传-Fast Retransimit做的事情有:

(1) 调整门限ssthresh的值为当前cwnd值的1/2; 
(2) 将cwnd值设置为新的ssthresh的值; 
(3) 重新进入拥塞避免阶段。

在快速重传的时候,一般网络只是轻微拥堵,在进入拥塞避免后,cwnd恢复的比较慢。针对这个,“快速恢复”算法被添加进来,当收到3个冗余ACK时,TCP最后的[3]步骤进入的不是拥塞避免阶段,而是快速恢复阶段。

4. 快速恢复算法–Fast Recovery:

快速恢复的思想是“数据包守恒”原则,即带宽不变的情况下,在网络同一时刻能容纳数据包数量是恒定的。当“老”数据包离开了网络后,就能向网络中发送一个“新”的数据包。既然已经收到了3个冗余ACK,说明有三个数据分段已经到达了接收端,既然三个分段已经离开了网络,那么就是说可以在发送3个分段了。于是只要发送方收到一个冗余的ACK,于是cwnd加1个MSS。快速恢复步骤如下(在进入快速恢复前,cwnd 和 sshthresh已被更新为:sshthresh = cwnd /2,cwnd = sshthresh):

(1) 把cwnd设置为ssthresh的值加3,重传Duplicated ACKs指定的数据包

(2) 如果再收到 duplicated Acks,那么cwnd = cwnd +1

(3) 如果收到新的ACK,而非duplicated Ack,那么将cwnd重新设置为3.中(1)的sshthresh的值。然后进入拥塞避免状态。

细心的同学可能会发现快速恢复有个比较明显的缺陷就是:它依赖于3个冗余ACK,并假定很多情况下,3个冗余的ACK只代表丢失一个包。但是3个冗余ACK也很有可能是丢失了很多个包,快速恢复只是重传了一个包,然后其他丢失的包就只能等待到RTO超时了。超时会导致ssthresh减半,并且退出了Fast Recovery阶段,多个超时会导致TCP传输速率呈级数下降。出现这个问题的主要原因是过早退出了Fast Recovery阶段。为解决这个问题,提出了New Reno算法,该算法是在没有SACK的支持下改进FastRecovery算法(SACK改变TCP的确认机制,把乱序等信息会全部告诉对方,SACK本身携带的信息就可以使得发送方有足够的信息来知道需要重传哪些包,而不需要重传哪些包),具体改进如下:

1) 发送端收到3个冗余ACK后,重传冗余ACK指示可能丢失的那个包segment1,如果segment1的ACK通告接收端已经收到发送端的全部已经发出的数据的话,那么就是只丢失一个包,如果没有,那么就是有多个包丢失了。

2) 发送端根据segment1的ACK判断出有多个包丢失,那么发送端继续重传窗口内未被ACK的第一个包,直到sliding window内发出去的包全被ACK了,才真正退出Fast Recovery阶段。

我们可以看到,拥塞控制在拥塞避免阶段,cwnd是加性增加的,在判断出现拥塞的时候采取的是指数递减。为什么要这样做呢?这是出于公平性的原则,拥塞窗口的增加受惠的只是自己,而拥塞窗口减少受益的是大家。这种指数递减的方式实现了公平性,一旦出现丢包,那么立即减半退避,可以给其他新建的连接腾出足够的带宽空间,从而保证整个的公平性。

至此,TCP的疑难杂症基本介绍完毕了,总的来说TCP是一个有连接的、可靠的、带流量控制和拥塞控制的端到端的协议。TCP的发送端能发多少数据,由发送端的发送窗口决定(当然发送窗口又被接收端的接收窗口、发送端的拥塞窗口限制)的,那么一个TCP连接的传输稳定状态应该体现在发送端的发送窗口的稳定状态上,这样的话,TCP的发送窗口有哪些稳定状态呢?TCP的发送窗口稳定状态主要有下面三种稳定状态:

【1】接收端拥有大窗口的经典锯齿状

大多数情况下都是处于这样的稳定状态,这是因为,一般情况下机器的处理速度就是比较快,这样TCP的接收端都是拥有较大的窗口,这时发送端的发送窗口就完全由其拥塞窗口cwnd决定了;网络上拥有成千上万的TCP连接,它们在相互争用网络带宽,TCP的流量控制使得它想要独享整个网络,而拥塞控制又限制其必要时做出牺牲来体现公平性。于是在传输稳定的时候TCP发送端呈现出下面过程的反复:

[1]用慢启动或者拥塞避免方式不断增加其拥塞窗口,直到丢包的发生; 
[2]然后将发送窗口将下降到1或者下降一半,进入慢启动或者拥塞避免阶段(要看是由于超时丢包还是由于冗余ACK丢包),过程如下图:

图片描述

【2】接收端拥有小窗口的直线状态

这种情况下是接收端非常慢速,接收窗口一直很小,这样发送窗口就完全有接收窗口决定了。由于发送窗口小,发送数据少,网络就不会出现拥塞了,于是发送窗口就一直稳定的等于那个较小的接收窗口,呈直线状态。

【3】两个直连网络端点间的满载状态下的直线状态

这种情况下,Peer两端直连,并且只有位于一个TCP连接,那么这个连接将独享网络带宽,这里不存在拥塞问题,在他们处理能力足够的情况下,TCP的流量控制使得他们能够跑慢整个网络带宽。

通过上面我们知道,在TCP传输稳定的时候,各个TCP连接会均分网络带宽的。相信大家学生时代经常会发生这样的场景,自己在看视频的时候突然出现视频卡顿,于是就大叫起来,哪个开了迅雷,赶紧给我停了。其实简单的下载加速就是开启多个TCP连接来分段下载就达到加速的效果,假设宿舍的带宽是1000K/s,一开始两个在看视频,每人平均网速是500k/s,这速度看起视频来那叫一个顺溜。突然其中一个同学打打开迅雷开着99个TCP连接在下载爱情动作片,这个时候平均下来你能分到的带宽就剩下10k/s,这网速下你的视频还不卡成幻灯片。在通信链路带宽固定(假设为W),多人公用一个网络带宽的情况下,利用TCP协议的拥塞控制的公平性,多开几个TCP连接就能多分到一些带宽(当然要忽略有些用UDP协议带来的影响),然而不管怎么最多也就能把整个带宽抢到,于是在占满整个带宽的情况下,下载一个大小为FS的文件,那么最快需要的时间是FS/W,难道就没办法加速了吗?

答案是有的,这样因为网络是网状的,一个节点是要和很多几点互联的,这就存在多个带宽为W的通信链路,如果我们能够将要下载的文件,一半从A通信链路下载,另外一半从B通信链路下载,这样整个下载时间就减半了为FS/(2W),这就是p2p加速。相信大家学生时代在下载爱情动作片的时候也遇到过这种情况,明明外网速度没这么快的,自己下载的爱情动作片的速度却达到几M/s,那是因为,你的左后或右后的宿友在帮你加速中。我们都知道P2P模式下载会快,并且越多人下载就越快,那么问题来了,P2P下载加速理论上的加速比是多少呢?

附加题1:P2P理论上的加速比

传统的C/S模式传输文件,在跑满Client带宽的情况下传输一个文件需要耗时FS/BW,如果有n个客户端需要下载文件,那么总耗时是n*(FS/BW),当然啦,这并不一定是串行传输,可以并行来传输的,这样总耗时也就是FS/BW了,但是这需要服务器的带宽是n个client带宽的总和n*BW。C/S模式一个明显的缺点是服务要传输一个文件n次,这样对服务器的性能和带宽带来比较大的压力,我可以换下思路,服务器将文件传给其中一个Client后,让这些互联的Client自己来交互那个文件,那服务器的压力就减少很多了。这就是P2P网络的好处,P2P利用各个节点间的互联,提倡“人人为我,我为人人”。

知道P2P传输的好处后,我们来谈下理论上的最大加速比,为了简化讨论,一个简单的网络拓扑图如下,有4个相互互联的节点,并且每个节点间的网络带宽是BW,传输一个大小为FS的文件最快的时间是多少呢?假设节点N1有个大小为FS的文件需要传输给N2,N3,N4节点,一种简单的方式就是:节点N1同时将文件传输给节点N2,N3,N4耗时FS/BW,这样大家都拥有文件FS了。大家可以看出,整个过程只有节点1在发送文件,其他节点都是在接收,完全违反了P2P的“人人为我,我为人人”的宗旨。那怎么才能让大家都做出贡献了呢?解决方案是切割文件。

(1) 首先,节点N1 文件分成3个片段FS2、FS3、FS4,接着将FS2发送给N2,FS3发送给N3,FS4发送给N4,耗时FS/(3*BW)

(2) 然后,N2,N3,N4执行“人人为我,我为人人”的精神,将自己拥有的F2,F3,F4分别发给没有的其他的节点,这样耗时FS/(3*BW)完成交换。

于是总耗时为2*FS/(3*BW)完成了文件FS的传输,可以看出耗时减少为原来的2/3了,如果有n个节点,那么时间就是原来的2/(n-1),也就是加速比是2/(n-1),这就是加速的理论上限了吗?还没发挥最多能量的,相信大家已经看到分割文件的好处了,上面的文件分割粒度还是有点大,以至于,在第二阶段(2)传输过程中,节点N1无所事事。为了最大化发挥大家的作用,我们需要将FS2、FS3、FS4再进行分割,假设将它们都均分为K等份,这样就有FS21,FS22…FS2K、FS31,FS32…FS3K、FS41,FS42…FS4K,一共3K个分段。于是下面就开始进行加速分发:

[1]节点N1将分段FS21,FS31,FS41分别发送给N2,N3,N4节点。耗时,FS/(3K*BW)

[2]节点N1将分段FS22,FS32,FS42分别发送给N2,N3,N4节点,同时节点N2,N3,N4将阶段[1]收到的分段相互发给没有的节点。耗时,FS/(3K*BW)

……

[K]节点N1将分段FS2K,FS3K,FS4K分别发送给N2,N3,N4节点,同时节点N2,N3,N4将阶段[K-1]收到的分段相互发给没有的节点。耗时,FS/(3K*BW)

[K+1]节点N2,N3,N4将阶段[K]收到的分段相互发给没有的节点。耗时,FS/(3K*BW)

于是总的耗时为(K+1)*(FS/(3K*BW))=FS/(3*BW)+FS/(3K*BW),当K趋于无穷大的时候,文件进行无限细分的时候,耗时变成了FS/(3*BW),也就是当节点是n+1的时候,加速比是n。这就是理论上的最大加速比了,最大加速比是P2P网络节点个数减1。

图片描述

附加题2:系统调用listen()的backlog参数指的是什么

要说明backlog参数的含义,首先需要说一下Linux的协议栈维护的TCP连接的两个连接队列:[1]SYN半连接队列;[2]accept连接队列

[1] SYN半连接队列:Server端收到Client的SYN包并回复SYN,ACK包后,该连接的信息就会被移到一个队列,这个队列就是SYN半连接队列(此时TCP连接处于 非同步状态)

[2] accept连接队列:Server端收到SYN,ACK包的ACK包后,就会将连接信息从[1]中的队列移到另外一个队列,这个队列就是accept连接队列(这个时候TCP连接已经建立,三次握手完成了)

用户进程调用accept()系统调用后,该连接信息就会从[2]中的队列中移走。

相信不少同学就backlog的具体含义进行争论过,有些认为backlog指的是[1]和[2]两个队列的和。而有些则认为是backlog指的是[2]的大小。其实,这两个说法都对,在linux kernel 2.2之前backlog指的是[1]和[2]两个队列的和。而2.2以后,就指的是[2]的大小,那么在kernel 2.2以后,[1]的大小怎么确定的呢?两个队列的作用分别是什么呢?

1. SYN半连接队列的作用

对于SYN半连接队列的大小是由(/proc/sys/net/ipv4/tcp_max_syn_backlog)这个内核参数控制的,有些内核似乎也受listen的backlog参数影响,取得是两个值的最小值。当这个队列满了,Server会丢弃新来的SYN包,而Client端在多次重发SYN包得不到响应而返回(connectiontime out)错误。但是,当Server端开启了syncookies,那么SYN半连接队列就没有逻辑上的最大值了,并且/proc/sys/net/ipv4/tcp_max_syn_backlog设置的值也会被忽略。

2. accept连接队列

accept连接队列的大小是由backlog参数和(/proc/sys/net/core/somaxconn)内核参数共同决定,取值为两个中的最小值。当accept连接队列满了,协议栈的行为根据(/proc/sys/net/ipv4/tcp_abort_on_overflow)内核参数而定。如果tcp_abort_on_overflow=1,server在收到SYN_ACK的ACK包后,协议栈会丢弃该连接并回复RST包给对端,这个是Client会出现(connectionreset by peer)错误。如果tcp_abort_on_overflow=0,server在收到SYN_ACK的ACK包后,直接丢弃该ACK包。这个时候Client认为连接已经建立了,一直在等Server的数据,直到超时出现readtimeout错误。

http://geek.csdn.net/news/detail/114503

参考资料

  • http://blog.csdn.net/dog250/article/details/6612496
  • http://coolshell.cn/articles/11564.html
  • http://coolshell.cn/articles/11609.html
  • http://www.tcpipguide.com/free/t_TCPMessageSegmentFormat.htm

 

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. unity3D赛车游戏项目源代码

    unity3D赛车游戏项目代码,分赛车和越野警车两种,仿真实赛车设计,很有身临其境的感觉,包含换挡系统和汽车碰撞,c#脚本。 下载地址: http://www.googln.net/thread-66571-1-1.html...

    2024/4/17 17:31:16
  2. Exchange & Lotus Notes邮件系统在线批量迁移账号及邮件

    直到今日,对邮件系统管理员来说,最大的挑战仍然是如何使用 “无痛”方法,从旧服务器往新服务器迁移全部的用户和数据。这个问题经典的解决方法是使用一个自定义程序直接从旧服务器的数据库中提取数据,然后将其导入新服务器的数据库。这里的问题是如何找到一个安全、可靠,并…...

    2024/4/18 18:44:24
  3. 一个案例讲解获取字符串长度的函数mb_strlen()和字符串截取函数mb_substr()

    这是在项目中遇到的一小段,包含了mb_strlen()和mb_substr()两个函数:> function _cut($_string,$_strlen){ > if(mb_strlen($_string,utf-8)>$_strlen){ > $_string=mb_substr($_string,0,$_strlen,utf-8).... ; > } }其中: mb_strlen()是…...

    2024/4/17 17:31:23
  4. Android中内存泄漏超级精炼详解

    一、前期基础知识储备(1)什么是内存?JAVA是在JVM所虚拟出的内存环境中运行的,JVM的内存可分为三个区:堆(heap)、栈(stack)和方法区(method)。栈(stack):是简单的数据结构,但在计算机中使用广泛。栈最显著的特征是:LIFO(Last In, First Out, 后进先出)。后来者居上。(跟…...

    2024/4/17 17:30:34
  5. 完全用链表实现的贪吃蛇

    1.链表设计 同事突然说想实现一个贪吃蛇,这使我想起了几年前实现的一个很糟糕的贪吃蛇程序,代码可以在《一个java写的贪吃蛇程序》里面找到。如今,突然想再实现一个贪吃蛇,不过这次绝对不能再那么糟糕了。用链表实现并且只用链表实现贪吃蛇是一个不错的主意,于是初步的打算…...

    2024/4/17 17:32:36
  6. tcp三次握手,四次挥手,ssl握手协议

    三次握手图中ack为ackbit,也就是ack标志位 (1)客户端发送连接请求,synbit为1,并且初始化一个随机序列号(客户端为SYN_SENT状态) (2)服务端收到请求,同意请求,分配空间,返回synack段给客户端,其中synbit为1,ackbit为1,acknum为客户端初始序列号+1,同时产生一个…...

    2024/4/20 14:10:19
  7. 基于Winpcap的邮件还原系统的实现

    吴志强,马春波,敖发良 时间:2011年05月09日 来源:微型机与应用2011年第2期摘 要: 随着互联网的普及,SMTP/POP3协议传输方式下的邮件已成为最简便、最经济的通信方式,但许多有害的邮件信息也随之而来。针对这些问题,在VC开发环境下,研究并实现了基于Winpcap的邮件监控及…...

    2024/4/19 4:18:13
  8. Java GUI-贪吃蛇游戏实现(含源码和静态资源)

    文章目录一、Java-GUI实现贪吃蛇游戏一)游戏思路详解及代码实现1. 程序结构2. 静态资源包3. 数据资源类4. 游戏主启动类5. 游戏面板绘制类 一、Java-GUI实现贪吃蛇游戏 一)游戏思路详解及代码实现 1. 程序结构2. 静态资源包作用此包用来存放游戏中需要用到的图片资源具体分类…...

    2024/4/19 10:59:26
  9. TCP三次握手第三次握手时ACK丢失怎么办

    如果此时ACK在网络中丢失,那么Server端该TCP连接的状态为SYN_RECV,并且依次等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5。 如果重发指定次数后,仍然未…...

    2024/4/4 23:20:35
  10. C语言实现求字符串的长度

    C语言实现strlen()求字符串的长度。 用递归和循环的方法求 #include<stdio.h> #include<stdlib.h>int strlen_di(char arr[])//递归方法 {if (arr[0] == \0){return 0;}return 1 + strlen_di(arr + 1); }int strlen_xun(char arr[])//循环方法 {int i = 0;while …...

    2024/5/2 12:43:02
  11. Jenkins 使用系统设置模板发送邮件

    1.系统管理-》系统设置接上图:接上图:点击Content Token Reference 右边的 ? 可以查看插件可用变量的说明。Default Triggers 按钮点开,选择Always此处的设置完成后无法进行调试,需要在job 中体现。此处勾选了Always 依然需要在job 中指定触发器。上图中邮件内容模板:<…...

    2024/5/2 16:45:04
  12. C++(qt)游戏实战项目:坦克大战(六源代码)

    坦克大战五叙述了如何发射子弹。到此坦克大战的核心功能基本完成到此献上源代码链接qt坦克大战源代码 此源代码敌人和玩家都用的Tank类,如果你们愿意也可以从Tank类继承,即按照C++(qt)游戏实战项目:坦克大战(前言)的类目结构来安排此源代码已实现的功能 地图编辑状态m:地…...

    2024/5/2 18:45:34
  13. C++进阶与拔高(九)(C++内存管理)(智能指针与内存泄漏)

    第四章 C++内存管理C++内存管理几乎存在于程序设计的方方面面,内存泄漏在每个C++程序中都有可能发生。参考网上大佬的博客,我们在这章对C++内存管理有一个大致的认识。本章包括内存管理,内存泄漏以及内存回收。C++测试岗位和开放岗位的面试很看重这一部分,因此很有必要说一…...

    2024/4/20 14:10:37
  14. TCP三次握手四次挥手总结(流程、常见问题、会发生的攻击、防范方法)

    三次握手我们先明确两个定义: 1,client为数据发送方 2,server为数据接收方好,下面进行三次握手的总结: 1,client想要向server发送数据,请求连接。这时client想服务器发送一个数据包,其中同步位(SYN)被置为1,表明client申请TCP连接,序号为j。 2,当server接收到了…...

    2024/4/17 17:31:05
  15. MATLAB版贪吃蛇

    思路: 界面,坐标轴 snake,数组 移动,更新snake坐标 操作: 上、下、左、右,移动 Esc,重新开始function snake(m, varargin) % 贪吃蛇,m*n y = m; if nargin == 1x = y; elsex = varargin{1}; end if y<4 || x<4return end%% 迷宫框 figure(KeyPressFcn…...

    2024/4/17 17:32:13
  16. linux shell 字符串获取长度、替换、截取、删除等操作(持续更新)

    测试字符串:str=/xxx/file.txt.gz一、长度、变量:说明 表达式 例子 结果 获取长度 ${#string} ${#str} 16 列出所有以prefix开头的变量 ${!prefix*}、${!prefix@} ${!st@} str测试${!prefix*}、${!prefix@}没什么区别,如果大神知道区别,留言,膜拜!str111=/xxx/f…...

    2024/4/17 17:31:49
  17. 前后端分离的后台管理系统 EL-ADMIN

    EL-ADMIN EL-ADMIN 基于 Spring Boot 2.1.0 、 Jpa、 Spring Security、redis、Vue的前后端分离的后台管理系统, 权限控制的方式为RBAC,项目支持数据字典与数据权限管理,支持一键生成前后端代码,支持前端菜单动态路由 开发文档 https://docs.auauz.net/ 体验地址 https:/…...

    2024/4/20 17:18:15
  18. 五子棋的c++代码

    设计步骤 很久没写这样的小游戏了,就是想写一个五子棋小游戏,以后代码有改进的地方我会继续发帖的,希望大家多多指导。游戏包含7个部分:五子棋的欢迎界面、棋盘初始化界面、游戏规则说明部分、棋子和棋盘显示界面、判断下棋点是否越界或已有棋子(我分成黑棋、白棋两个部分…...

    2024/4/11 19:02:40
  19. gocron - 定时任务管理系统

    gocron - 定时任务管理系统项目简介使用Go语言开发的轻量级定时任务集中调度和管理系统, 用于替代Linux-crontab 查看文档原有的延时任务拆分为独立项目延迟队列 功能特性Web界面管理定时任务 crontab时间表达式, 精确到秒 任务执行失败可重试 任务执行超时, 强制结束 任务依赖…...

    2024/4/17 17:31:16
  20. 如何求C语言字符串长度(strlen函数和sizeof关键字)

    原文出处:http://blog.csdn.net/kstrwind/article/details/8036555 ----------------------------------------------------------------------------------------------------------------------------------------------------------C语言字符串长度的计算是编程时常用到的,…...

    2024/4/25 19:53:12

最新文章

  1. 通信接口——时钟和信号

    前言 所有接口只要抓住三个核心点就能分清&#xff1a;时钟同步和异步&#xff0c;时钟的来源&#xff0c;信号的传输方向。 一、时钟同步和异步 接口之间的交互方式存在多种形式&#xff0c;如果按照是否有公共时钟CLK的参与&#xff0c;可以分为同步传输和异步传输。 同步&…...

    2024/5/2 21:34:04
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 职场口才提升之道

    职场口才提升之道 在职场中&#xff0c;口才的重要性不言而喻。无论是与同事沟通协作&#xff0c;还是向上级汇报工作&#xff0c;亦或是与客户洽谈业务&#xff0c;都需要具备良好的口才能力。一个出色的职场人&#xff0c;除了拥有扎实的专业技能外&#xff0c;还应具备出色…...

    2024/5/1 2:36:04
  4. 【单调队列】滑动窗口与子矩阵

    一、滑动窗口 给定一个大小为 n≤1e6 的数组。 有一个大小为 k 的滑动窗口&#xff0c;它从数组的最左边移动到最右边。 你只能在窗口中看到 k 个数字。 每次滑动窗口向右移动一个位置。 以下是一个例子&#xff1a; 该数组为 [1 3 -1 -3 5 3 6 7]&#xff0c;k 为 3。 …...

    2024/4/30 2:12:58
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/2 16:16:39
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/2 9:28:15
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/2 15:04:34
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57