西宁网站建设开发,如何做网站长尾关键词布局,动漫设计专业主要学什么,简单的安卓app开发实例TCP实现可靠传输的实现 目录TCP实现可靠传输的实现ARQ协议停止等待协议#xff08;古老#xff09;连续ARQ协议累计重传#xff08;回退N帧的ARQ协议#xff09;缓存确认#xff08;选择重传ARQ协议#xff09;超时重传的时间选择TCP的流量控制零窗口探测报文段Nagle算法…TCP实现可靠传输的实现 目录TCP实现可靠传输的实现ARQ协议停止等待协议古老连续ARQ协议累计重传回退N帧的ARQ协议缓存确认选择重传ARQ协议超时重传的时间选择TCP的流量控制零窗口探测报文段Nagle算法TCP的拥塞控制TCP的拥塞控制方法路由器主动队列管理AQM参考ARQ协议
为了方便表示我们在本小节中将A叫做发送方而B叫做接收方。
停止等待协议古老
停止等待就是每发送完一个分组就停止发送等待对方的确认。在收到确认后再发送下一个分组。这其实就有点类似与半双工了。
停止等待协议的工作原理可以通过下图了解。 理解停止等待协议只要根据上图看图说话就行。在无错误状态下A发送消息后在收到B返回的确认消息后再发出下一条消息。上图中的(b)则说明了若出现发送方报文出错重传的机制。下图展现了另外两种可能出现重传的情况。 有一些细节需要注意
A在发送完一个分组后必须暂时保留已发送的分组的副本分组和确认分组都必须进行编号。这样才能明确时哪一个发送出去的分组收到了确认而哪一个分组还没有收到确认。比如出现已失效的连接请求报文段超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。需要考虑到网络中出现的时延和拥塞问题。
停止等待协议的优点是比较简单但是信道利用率低。 根据上图我们此时信道的利用率U可以粗略地通过下式来计算 UTDTDRTTTAU \frac{T_D}{T_D RTT T_A} UTDRTTTATD
连续ARQ协议
通过前面的介绍我们可以知道停止等待协议的传输效率太低。我们可以想到用下图这种流水线的传输方式显然这样可以提高信道的利用率。但是这也会带来新的问题可以可以通过滑动窗口协议搭配不同的确认方式来解决 累计重传回退N帧的ARQ协议 滑动窗口协议限定了一次性发送数据的条数同时限定了如何发送下一组请求。我们搭配着上面这副图来理解累计重传的原理。
例如发送方一次性发送了5个分组但是第二个分组丢失了。这个 时候接收方只能对第一个分组进行确认。发送方无法确认后面四个分组中还有哪个是传到了的于是只好将后后面的四个分组全部重传。这也就出现了上图中滑动窗口向右滑动一个序号的原因这就叫做Go-back-N回退N。 采用累计确认的方式时接收方不必对收到的分组逐个发送确认而是在收到几个分组后对按序到达的最后一个分组发送确认 通过这种多个重传的案例可以清楚地知道连续ARQ在通信线路质量不好时带来的负面影响。
缓存确认选择重传ARQ协议 我看别的很多都称这种方式为选择重传但感觉根据自己的理解这个叫做缓存确认更容易理解。通过上图我们可以看到在接收方可发送方分别需要维护一个发送缓存和一个接收缓存。
同样的我们对照着下图来理解缓存确认的运作原理。例如A已经发送了34-41分组中的数据但是其中37、38、40都没有按照顺序被B收到。对于这三个未按序到达的数据而言可能是提早到、晚到、没传到。我举以下两个例子
① 37、38、40 都提前到了
在数据提前到的时候这些数据会先被B存放在自己的接收缓存中。当收到了36号数据后37、38依次接上并分别发送确认报文。40则在收到39后再接入。如果过程中出现超时也会触发A的重传
②37没传到 38、40都提前到了
这个时候接收方最高发送的确认报文是36。而37号报文由于超时A重新发送37这部分的数据同时滑动窗口也会往后面移动并发送42、43、44这三个序号的数据。 这里其实每次A收到确认号落在发送窗口内考虑到“已失效的连接请求报文段”那么A就可以使滑动窗口继续向前移动。 发送缓存用来暂时存放
发送应用程序传送给发送方TCP准备发送的数据TCP已发出但尚未收到确认的数据
接收缓存用来暂时存放
按序到达的、但尚未被接受应用程序读取的数据未按序到达的数据 根据前面的了解我们需要注意以下三点
虽然A的发送窗口是根据B的接收窗口设置的但再同一时刻A的发送窗口并不总是和B的接收窗口一样大可以小于接收窗口。对于不按序到达的数据如何处理TCP标准并无明确规定。如果接收方将不按序到达的数据一律丢弃这样对网络资源的利用不利。因此TCP通常对不按序到达的数据先临时存放再接收窗口中等到字节流中缺少字节收到后再按序交付上层的应用程序。TCP要求接收方必须有累计确认的功能这样可以减小传输开销。接收方可以在合适的时候发送确认也可以在自己有数据要发送的时候把确认信息顺便捎带上。但TCP规定确认的推迟时间不应超过0.5秒。
超时重传的时间选择
TCP采用了一种自适应算法它记录了一个报文段发出的时间以及收到相应的确认的时间(可以去看TCP尾部的选项字段)。这两个时间之差就是报文段的往返时间RTT。TCP保留了一个RTT的一个加权平均往返时间RTTs也叫平滑的往返时间。每当第一次测量到RTT样本值。但以后每测量到一个新的RTT样本就按下式重新计算依次RTTs 新的RTTs(1−α)×(旧的RTTs)α×(新的RTT样本)新的RTTs (1 - \alpha) \times (旧的RTTs) \alpha \times (新的RTT样本) 新的RTTs(1−α)×(旧的RTTs)α×(新的RTT样本) 一般认为RTT样本值对新的RTTs的值影响较大RFC 3298 推荐的α\alphaα值为0.125。**超时重传时间 RTORetransmission Time-Out**应略大于上面得到的平滑RTTs。RFC 6298推荐使用下式计算RTO RTORTTs4×RTTDRTO RTTs 4 \times RTT_D RTORTTs4×RTTD 而RTTDRTT_DRTTD是RTT的偏差的加权平均值它与RTTs和新的RTT样本之差有关。 新的RTTD(1−β)×(旧的RTTD)β×∣RTTs−新的RTT样本∣新的RTT_D (1 - \beta) \times (旧的RTT_D) \beta \times|RTTs - 新的RTT样本| 新的RTTD(1−β)×(旧的RTTD)β×∣RTTs−新的RTT样本∣ 这里的β\betaβ是一个小于1的系数它的推荐值是0.25.
通过上面的公式我们就可以计算出重传时间RTO。但是我们在此时要考虑到超时重传时出现时**如何判定此报文段时对先发送的报文段的确认还是对后来重传报文段的确认**由于重传的报文段和原来的报文段完全一样因源主机在收到确认后就无法做出正确的判断而正确的判断对确定平均RTTs 的值关系很大影响关系可以通过下图看出。 于是又了Karn算法在计算加权平均RTTS时只要报文段重传了就不采用其往返时间样本。这样就得出了加权平均RTTS和RTO就较准确。
但是若出现报文段的时延突然增大很多。若不考虑重传的报文段重传时间继续按照原来的RTO。将会导致出现大量的重传。
于是有了改进方法是报文段每重传依次就把超时重传时间RTO增大一些(经典的做法是2倍)。当不再发生报文段的重传时才根据RTO的计算公式计算超时重传。
TCP的流量控制
所谓的流量控制就是让发送方的速率不要太快要让接收方来得及接收。(注意流量控制是一种接收方对发送方来讲的机制是一个端到端的问题)
利用滑动窗口机制可以比较方便地在TCP连接上实现对发送方的流量控制。
现在我们假定数据流向是单向的也就是说发送方A只负责发送数据不负责处理和接受数据接收方B只负责处理和接收数据并且对接收到的数据进行应答ACK。
在A和B建立连接的时候B将自己的接收窗口RWND(receiver window)设置为400字节。这时候A将自己的发送窗口也设置为400如下图所示。A给B连续发送了3个TCP报文段每个报文段都包含100字节的数据其中第三个TCP报文段因某种网络原因丢失。同时A收到了来自B的应答报文段B调整接收窗口rwnd 300。此时发送窗口应该是在301-500.于是A就继续发送301-400401-500这两段报文。这时也触发了A201-300这段报文的超时重传。随后收到了对401-500这段报文的确认这个时候说明前五段报文都已经被B收到了并设置rwnd 100。于是A根据rwnd再次调节发送窗口为100字节此时发送窗口移动到了501-600的位置。在收到501-600这段报文后根据rwnd 0将发送窗口设置为0。
此时A需要等待B发送的新的接收窗口大小rwnd 0才能继续发送数据。于是B向A发送更新自己rwnd的报文但是意外出现了这个更新报文段丢失此时将会导致A在等待B的rwndB在等待A的新数据于是出现了死锁局面。 零窗口探测报文段
为了防止这种意外的发生我们设置A在收到B的0接收窗口大小rwnd0时会自动启动一个“持续计时器”,当持续计时器timeout时如果还没有收到来自B的rwnd更新报文段则会发送一个零窗口探测报文段携带1字节数据当B接收到这个TCP报文段后会给A回复一个rwnd的更新如果此时rwnd 0那么A就可以继续发送数据如果rwnd0则重新启动一个持续计时器重复上述步骤。
这也出现了另外一个问题糊涂窗口综合征当B对应的交互式应用进程每次仅仅接收缓存中的1字节数据这样使接收缓存空间仅腾出1字节如果这个时候刚好收到了零窗口探测报文段就会将rwnd设置为1这样发送方就只能发送来1个字节的数据.这样进行下去使网络的效率很低。
解决这个问题的方案是
让接受方等待一段时间使得接收缓存已有足够空间容纳一个最长报文段MSS或者等到接收缓存已有一般空闲空间。只要出现两种情况之一接收方就发出确认报文并向发送方通知当前的窗口大小。
Nagle算法
为理解Nagle算法 我们可以设想以下场景TCP的发送应用进程把要发送的数据逐字节地送到TCP发送缓存。这个时候为了提高网络的吞吐量Nagle算法规定
若应用进程把要发送的数据逐个字节地送到TCP的发送缓存则发送方就把第一个数据字节先发送出去把后面到达的数据字节都缓存起来。当发送方收到对第一个数据字符的确认后再把发送缓存中的所有数据组装成一个报文段发送出去同时继续对随后到达的数据进行缓存。Nagle算法还规定当已到达发送缓存的数据已达到发送窗口的一半或已到达报文段的最大长度时就立即发送一个报文段。
TCP的拥塞控制
在某段时间内如果网络中某一资源的需求超过了该资源所能提供的可用部分网络的性能就要变坏。这种情况就叫做拥塞。可以把出现网络拥塞的条件写成如下式子 ∑对资源的需求可用资源\sum 对资源的需求 可用资源 ∑对资源的需求可用资源 拥塞控制就是防止过多的数据注入到网络中这样可用使网络中的路由器或链路不至于过载。拥塞控制是一个全局性的过程。 提供的负载 代表单位时间内输入给网络的分组数目。吞吐量 代表单位时间内从网络输出的分组数目 TCP的拥塞控制方法
TCP进行拥塞控制的算法有四种慢开始、拥塞避免、快重传和快恢复。
下面考虑的拥塞窗口是基于滑动窗口协议的。发送发维护了一个**拥塞窗口cwndcongestion window**的状态变量。同时认为发送方超时计时器启动时就判断网络出现拥塞。因为传输出差错而丢失分组的可能性比较小。 慢开始算法
慢开始就是由小到达逐渐增大注入网络中的数据字节或者说是从小到大逐渐增大拥塞窗口数值。RFC5861规定初始的cwnd设置为不超过2至4个。
慢开始规定在每收到一个对新报文段的确认后可用把拥塞窗口增加最多一个SMSS的数值。为了避免cwnd过大还需要设置一个慢开始门限 ssthresh
当cwnd ssthresh时使用慢开始算法当cwnd ssthresh时使用拥塞避免算法当cwnd ssthresh时既可以使用慢开始算法也可使用拥塞避免算法。
拥塞避免算法
拥塞避免算法就是让cwnd缓慢增大。执行算法的过程大概是这样的每经过一个往返时间RTT发送方的拥塞窗口cwnd的大小就增加1。拥塞避免并非完全避免拥塞而是让拥塞窗口增长得缓慢一些。
快重传算法
在发现有分组丢失认为网络出现了拥塞。如上图中的2号点。于是设置ssthresh cwnd / 2、cwnd 1。此时进入慢开始。在快重传算法中接收方需要对发送方的数据立即做出确认即使是失序且已接受的报文段也要做重复确认。如果发送方收到连续多条重复确认发送方知道了只是丢失了个别报文段于是开启快恢复。
快恢复算法
使ssthresh cwnd / 2同时设置cwnd ssthresh,并开始执行拥塞避免算法。
路由器主动队列管理AQM
前面讨论的TCP拥塞控制并没有和网络层采取的策略联系起来。网络层的策略对TCP影响最大的就是路由器的分组丢弃策略。路由器会维护一个先进先出的队列当队列已满后续排队的分组都将被丢弃。这就叫做尾部丢弃策略。
主动队列管理AQMactive Queue Management 可用由不同的实现方法。其中**随机早期检验RED(Random Early Edtection)**是其中比较流行的。使用RED需要路由器维护两个参数最小门限和最大门限。当每一个分组到达的时RED就按照规定的算法先计算当前的平均队列的长度。并按照一下三种情况处理新的分组
平均队列的长度 最小门限则把新到的分组放入队列进行排队平均队列的长度 最大门限则把新到达的分组丢弃最小门限 平均队列的长度 最大门限,按照一定的概率p把新到达的分组丢弃体现了分组丢弃的随机性。
RED随机丢弃分组对应第三种情况是因为检测到网络拥塞的早期征兆。
参考
《计算机网络 第7版》《计算机网络 第8版》TCP的流量控制