当前位置: 首页 > news >正文

北京外贸网站建设专业网站设计开发网站

北京外贸网站建设,专业网站设计开发网站,自建网站营销是什么,WordPress 后台反应好慢简单聊聊 TCP 协议 如何实现可靠传输 ?完全可靠存在比特差错存在丢包流水线可靠数据传输协议回退N步 (GBN)选择重传 (ARQ) 小结 TCPTCP 连接报文段结构序号和确认号 可靠数据传输避免重传超时时间加倍快速重传回退N步还是选择重传 流量控制连接管理拥塞控制拥塞原因拥塞控制方… 简单聊聊 TCP 协议 如何实现可靠传输 ?完全可靠存在比特差错存在丢包流水线可靠数据传输协议回退N步 (GBN)选择重传 (ARQ) 小结 TCPTCP 连接报文段结构序号和确认号 可靠数据传输避免重传超时时间加倍快速重传回退N步还是选择重传 流量控制连接管理拥塞控制拥塞原因拥塞控制方法端到端拥塞控制如何限制发送速率 如何感知拥塞 拥塞控制算法慢启动拥塞避免快速恢复小结 公平性自私自利的UDP并行TCP连接 网络辅助拥塞控制 小结 本文参考自定向下一书第三章整理而来。 如何实现可靠传输 ? 在网络世界中最重要的问题之一就是可靠传输而运输层的TCP协议为上层实体提供的服务抽象就是: 数据可以通过一条可靠的信道进行传输。借助于可靠信道传输数据比特就不会受到损坏或者丢失而且所有数据都是按照其发送顺序进行交付。这也正是TCP向调用它的因特网所提供的服务模型。 TCP 是在不可靠的网络层之上实现的可靠数据传输协议所以这里的关键在于如何去设计这样一个可靠数据传输协议呢 完全可靠 假设底层的信道传输是绝对可靠的那么我们直接正常收发数据即可 存在比特差错 如果底层信道可能会发生比特差错那么两端此时都需要具备差错检测功能同时需要引入消息确认机制当任何一端接收到否定确认消息时都需要重传对应的分组 基于上面重传机制实现的可靠数据传输协议也被成为自动重传请求(ARQ)协议 方案二中发送方在发送完一个分组后必须等待直到接收到ACK或NAK响应后才能继续从上层获取更多的数据进行发送因此该协议也被成为停止等待协议。 方案二最大的缺陷在于没有考虑ACK和NAK分组受损的可能性我们可以为ACK或NAK分组也添加校验和进行差错检测但是我们无法知道接收方是否正确接收了上一块发送的数据。 解决这个问题或许有三个思考方向: 由于ACK和NAK分组是针对数据分组重传引入的所以我们可以考虑为ACK和NAK分组重传单独引入一组分组用于ACK和NAK分组的重传需求但是如果这里针对ACK和NAK分组重传对应的分组也出现差错了那又该怎么办呢 套娃不太现实那样会陷入递归的死循环中所以该方案不可取能否为ACK和NAK分组增加足够的校验和比特使得发送双方不仅可以检测差错还可恢复差错呢 当发送方接收到含糊不清的ACK或NAK分组时只需要重传当前数据分组即可但是该方案会在信道中引入冗余分组。 解决这个问题的一个简单办法就是引入序列号机制即为所有数据分组添加一个新的seq字段用于表示当前分组的序号在方案二中当接收方接收到一个受损分组后会响应一个NAK分组但是当我们引入了序列号机制时则可以通过对上次正确接收到的分组发送一个ACK达成和NAK一样的效果当发送方接收到对同一个分组的两个ACK (即接收到冗余ACK)时就知道接收方没有正确接收到跟在被确认两次的分组后面的分组了。 基于序列号机制我们便轻松实现了一个无NAK的可靠数据传输协议。 方案二假设底层信道不会产生分组丢失问题 存在丢包 方案三假定底层信道不仅会发生比特受损还会丢包那么这又引出了两个问题 : 怎样检测丢包以及丢包发生后我们应该做些什么。 检测丢包最直接的想法就是引入超时重传机制站在发送方的角度来看由于发送方不知道是一个分组丢失还是一个ACK丢失或者只是该分组或ACK过度延时。在所有这些情况下都可以采用超时重传来解决。 为了实现超时重传我们需要引入一个重传计时器发送方需要做以下几件事情: 每次发送一个分组时(第一次分组和重传分组)便启动一个定时器发送方还要能够响应定时器中断(重传当前未ACK的分组)终止定时器 (不存在未ACK的分组时) 引入了超时重传机制后我们来看一下当前协议在各种情况下的工作流程: 无丢包操作 分组丢失 丢失ACK 过早超时 方案三中最主要的一点就是超时时间的设置但是不管怎样我们已经可以利用检验和序号定时器ACK机制来实现一个可靠的数据传输协议了。 流水线可靠数据传输协议 方案三所设计的停止等待协议最大问题就在于无法充分利用底层网络带宽解决这个问题的办法就是采用流水线传输技术如下图所示: 采用流水线传输技术后我们需要针对方案三设计的停止等待协议进行如下改造: 停止等待协议中我们其实只使用两个序列号0和1就足以了但是流水线传输迫使我们必须增加序号范围因为每个输送中的分组都必须有一个唯一的序号而且也许有多个在传输中但是未被确认的报文。协议的发送方和接收方两端也需要缓存多个分组发送方至少能够缓存那些已经发送但还未确认的分组接收方需要缓存那些已经正确接收的分组。流水线的差错恢复也需要考虑是采用 回退N步(GBN) 还是 选择重传 (SR) 这也决定了所需序号范围和对缓存区大小的要求。 回退N步 (GBN) 在回退N步(GBN)协议中允许发送方发送多个分组而无需等待确认但它也受限于流水线中未确认的分组数不能超过某个最大允许数N。 发送方会在本端维护一个滑动窗口大小为N同时在发送端看到的发送缓存区的数据被分为了以下四部分: 已经被确认的字节流已发送还未被确认的字节流准备就绪待发送的字节流空闲空间 随着协议的运行该窗口在序号空间向前滑动。因此N通常被称为窗口长度GBN 协议也常被称为滑动窗口协议。 对于GBN协议来说他必须处理以下三类事件: 当上层调用send接口发送数据时发送器首先检查发送窗口是否已满即是否有N个已经发送但未被确认的分组如果未满则产生一个分组并将其发送并更新相关变量值如果满了发送器可以将数据暂时缓存起来或者使用同步机制让调用方等待直到窗口未满时。收到一个ACK响应时采用累积确认的方式表明接收方已经正确接收到序号为n的以前且包括n在内的所有分组。当出现定时器超时事件时发送方重传所有已发送但还未被确认过的分组这里发送方可以仅使用一个定时器作为最早的已发送但未被确认的分组所使用的定时器。如果收到一个ACK但仍有已发送但未被确认的分组则定时器被重新启动(刷新定时器)。如果没有已发送但未被确认的分组则停止该定时器。 GBN 协议采用累积确认方式即如果接收方收到了一个分组序号为n并且该分组按序到达那么接收方会为分组n发送一个ACK并将该分组中的数据全部交付给上层。如果分组未按序到达那么接收方会丢弃该分组并为最近按序接收的分组重新发送ACK。注意到因为一次交付给上层一个分组如果分组k已接收并交付则所有序号比k小的分组也以及交付。因此使用累积确认是GBN一个自然的选择。 在GBN协议中接收方会丢弃所有失序分组又因为接收方必须按序将数据交付给上层。假定现在期望接收分组n而分组n1却到了。因为数据必须按序交付接收方可能缓存保存分组n1然后在它收到并交付分组n后再将该分组交付到上层。然而如果分组n丢失则该分组及分组n1最终将在发送方根据GBN重传规则而被重传。 因此接收方只需丢弃分组n1即可。这种方法的优点是接收缓存简单即接收方不需要缓存任何失序分组从而接收缓冲区只需要维护一个nextSeq表示下一个按序接收的分组的序号即可。 当然丢弃一个正确接收的分组的缺点是随后对该分组的重传也许会丢失或出错因此甚至需要更多的重传。 上图给出了窗口长度为4个分组的GBN协议的运行情况。因为该窗口长度的限制发送方发送分组03然后在继续发送之前必须等待直到一个或多个分组被确认。当接收到每一个连续的ACK例如ACK0和ACK1时 该窗口便向前滑动发送方便可以发送新的分组分别是分组4和分组5。在接收方存在分组2丢失时分组3、4和5被发现是失序分组也会被丢弃。 搞懂GBN协议关键要弄明白按序到达时什么意思 选择重传 (ARQ) GBN协议允许发送方用多个分组“填充流水线”因此避免了停等协议中所提到的信道利用率问题。然而GBN本身也有一些情况存在着性能问题。尤其是当窗口长度和带宽时延积都很大时在流水线中会有很多分组更是如此。单个分组的差错就能够引起GBN重传大量分组许多分组根本没有必要重传。随着信道差错率的增加流水线可能会被这些不必要重传的分组所充斥。 选择重传SR协议通过让发送方仅重传那些它怀疑在接收方出错即丢失或受损的分组而避免了不必要的重传。这种个别的、按需的重传要求接收方逐个地确认正确接收的分组。再次用窗口长度N来限制流水线中未完成、未被确认的分组数。然而与GBN不同的是发送方已经收到了对窗口中某些分组的ACK。 SR 接收方将确认一个正确接收的分组而不管其是否按序到达。失序的分组将被缓存直到所有丢失分组(即序号更小的分组)皆被收到为止这时才可以将一批分组按序交付给上层。 下面我们先来看看SR发送方需要处理的事件有哪些: 从上层收到数据 当从上层接收到数据后SR发送方检查下一个可用于该分组的序号。如果序号位于发送方的窗口内则将数据打包并发送否则就像在GBN中一样要么将数据缓存要么将其返回给上层以便以后传输。超时 定时器再次被用来防止丢失分组。然而现在每个分组必须拥有其自己的逻辑定时器因为超时发生后只能发送一个分组。可以使用单个硬件定时器模拟多个逻辑定时器的操作。收到ACK 如果收到ACK倘若该分组序号在窗口内则SR发送方将那个被确认的分组标记为已接收。如果该分组的序号等于sendbase则窗口基序号向前移动到具有最小序号的未确认分组处。如果窗口移动了并且有序号落在窗口内的未发送分组则发送这些分组。 再来看看SR接收方需要处理的事件有哪些: 收到的分组落在接收方的窗口内一个选择ACK被回送给发送方。如果该分组以前没收到过则缓存该分组。如果该分组的序号等于接收窗口的基序号revbase则该分组以及以前缓存的序号连续的起始于revbase的分组交付给上层。然后接收窗口按向前移动分组的编号向上交付这些分组。序号在rev_base - Nrev_base - 1内的分组被正确收到。在此情况下必须产生一个ACK即使该分组是接收方以前已确认过的分组。其他情况。忽略该分组。 可以参考下图案例进行理解: 这里有一点很重要就是接收方需要重新确认而不是忽略已收到过的那些序号小于当前窗口基序号的分组这里可能是因为ack丢失导致发送方进行产生了重发所以需要回应一下。 小结 经过了上述讨论后我们来总结一下确保可靠数据传输的机制和相关用途: 校验和 : 用于检测一个传输分组中的比特错误定时器 : 用于超时/重传一个分组可能因为该分组(或其ACK)在信道中丢失了。由于当一个分组延时但未丢失或当一个分组已经被接收方收到但从接收方到发送方的ACK丢失时可能产生超时事件所以接收方可能会收到一个分组的多个冗余副本。序号 : 用于为从发送方流向接收方的数据分组按顺序编号。所接收分组的序号间的空隙可使接收方检测出丢失的分组。具有相同序号的分组可使接收方检测出一个分组的冗余副本。确认 : 接收方用于告诉发送方一个分组或一组分组已被正确地接收到了。确认报文通常携带着被确认的分组或多个分组的序号。确认可以是逐个的或累积的这取决于协议。否定确认 : 接收方用于告诉发送方某个分组未被正确地接收。否定确认报文通常携带着未被正确接收的分组的序号。窗口流水线 : 发送方也许被限制仅发送那些序号落在一个指定范围内的分组。通过允许一次发送多个分组但未被确认发送方的利用率可在停止等待模式的基础上得到增加。窗口的长度可根据接收方接收和缓存报文的能力网络中的拥塞程度或两者情况来进行设置。 上述方案假设过程中我们都默认分组在发送方和接收方之间的信道中不会被重新排序但是实际网络运行过程中分组重新排序是可能发生的。 分组重新排序的一个表现就是一个具有序号或确认号x的分组的旧副本可能会出现即使发送方或接收方的窗口中都没有包含x。对于分组重新排序信道可被看成基本上是在缓存分组并在将来任意时刻自然地释放出这些分组。由于序号可以被重新使用那么必须小心以免出现这样的冗余分组。实际应用中采用的方法是确保一个序号不被重新使用直到发送方“确信”任何先前发送的序号为x的分组都不再在网络中为止。通过假定一个分组在网络中的“存活”时间不会超过某个固定最大时间量来做到这一点。在高速网络的TCP扩展中最长的分组寿命被假定为大约3分钟。Sunshine 1978 中描述了一种使用序号的方法它能够完全避免重新排序问题感兴趣可以自行去了解一下。 TCP TCP是因特网运输层的面向连接的可靠的运输协议其主要使用包括差错检测重传累积确认定时器以及序号和确认号的首部字段实现可靠传输协议。 TCP 连接 TCP 协议是面向连接的协议连接建立前需要先经历三次握手断开时需要经历四次挥手。TCP 连接的组成包括: 一台主机上的缓存变量和与进程连接的套接字以及另一台主机上的另一组缓存变量和与进程连接的套接字。这两台主机之间的网络元素(路由器交换机和中继器)中没有为该连接分配任何缓存和变量。 这里的连接是一条逻辑连接其共同状态仅保留在两个通信端系统的TCP程序中中间的路由器对TCP连接完全视而不见它们看到的是数据报而不是连接。 其次TCP 连接总是点对点的不支持多播发起连接的进程被称为客户端进程而另一个进程被称为服务器进程。连接的建立由客户端发送一个特殊的TCP报文段开启服务器用另一个特殊的TCP报文段来响应。最后客户端再用第三个特殊报文段作为响应。前两个报文段不承载有效载荷也就是不包含应用层数据而第三个报文段可以承载有效载荷由于这两台主机之间发送了三个报文段所以这种连接建立过程通常被称为三次握手。 一旦建立起了一条TCP连接两个应用进程之间就可以相互发送数据了。TCP会在两端都维护一个发送缓存和接收缓存TCP会在方便的时候从发送缓存中取出最多MSS(最大报文段长度)大小的数据。 MSS通常根据最初确定的由本地发送主机发送的最大链路层帧长度即所谓的最大传输单元Maximum Transmission UnitMTU来设置。设置该MSS要保证一个TCP 报文段当封装在一个IP数据报中加上TCPIP首部长度通常40字节将适合单个链路层帧。以太网和PPP链路层协议都具有1500字节的MTU因此MSS的典型值为1460字节。已经提出了多种发现路径MTU的方法并基于路径MTU值设置MSS路径 MTU是指能在从源到目的地的所有链路上发送的最大链路层帧RFC 1191。注意到MSS是指在报文段里应用层数据的最大长度而不是指包括首部的TCP报文段的最大长度。 TCP为每块客户数据配上一个TCP首部从而形成多个TCP报文段TCP segment。这些报文段被下传给网络层网络层将其分别封装在网络层IP数据报中。然后这些IP数据报被发送到网络中。当TCP在另一端接收到一个报文段后该报文段的数据就被放入该TCP连接的接收缓存中。 由于TCP协议已经遵循MSS在传输层进行了分段处理所以网络层就无需通过IP协议再次分片和重组了与之相对的就是UDP协议还需要借助IP层进行分片处理: Linux 1.2.13 – IP分片重组源码分析 报文段结构 tcp 报文段结构如下所示: 下面针对其中部分重要字段展开说明: 32比特的序号字段和32比特的确认号字段。16比特的接收窗口字段该字段用于流量控制 -- 用于指示接收方愿意接受的字节数量。4比特的首部长度字段该字段指示了以32比特的字为单位的TCP首部长度。由于TCP选项字段的原因TCP首部的长度是可变的。通常选项字段为空所以TCP首部的典型长度是20字节。可选与变长的选项字段该字段用于发送方与接收方协商最大报文段长度MSS时或在高速网络环境下用作窗口调节因子时使用。首部字段中还定义了一个时间戳选项。6比特的标志字段flag field: ACK比特用于指示确认字段中的值是有效的即该报文段包括一个对已被成功接收报文段的确认。RST、SYN 和 FIN 比特用于连接建立和拆除。在明确拥塞通告中使用了CWR和ECE比特。当PSH比特被置位时就指示接收方应立即将数据交给上层。最后 URG比特用来指示报文段里存在着被发送端的上层实体置为“紧急”的数据。 紧急数据的最后一个字节由16比特的紧急数据指针字段指出。当紧急数据存在并给出指向紧急数据尾指针的时候 TCP必须通知接收端的上层实体。 在实践中 PSH、 URG和紧急数据指针并没有使用。为了完整性起见我们才提到这些字段。 序号和确认号 TCP把数据看成一个无结构的、有序的字节流。我们从TCP对序号的使用上可以看出这一点因为序号是建立在传送的字节流之上而不是建立在传送的报文段的序列之上。一个报文段的序号因此是该报文段首字节的字节流编号。 TCP是全双工的因此主机A在向主机B发送数据的同时也许也接收来自主机B的数据都是同一条TCP连接的一部分。从主机 B 到达的每个报文段中都有一个序号用于表示从 B 流向 A 的数据。主机A 填充进报文段的确认号是主机 A 期望从主机 B 收到的下一字节的序号。 TCP协议采用的是累积确认法为了证明这一点我们来看下面这个例子: 假设主机A已收到一个来自主机B的包含字节0535的报文段以及另一个包含字节9001000的报文段。由于某种原因主机A还没有收到字节536899的报文段。在这个例子中主机A为了重新构建主机B的数据流仍在等待字节536和其后的字节。因此A到B的下一个报文段将在确认号字段中包含536。因为TCP只确认该流中至第一个丢失字节为止的字节所以TCP被称为提供累积确认。 当我们引入了序列号和确认号后我们还可以思考一下下面这个问题: 主机A在收到第二个报文段字节536899之前收到第三个报文段字节9001000会发生什么呢也就是说第三个报文段失序到达。该微妙的问题是当主机在一条TCP连接中收到失序报文段时该怎么办有趣的是TCP RFC并没有为此明确规定任何规则而是把这一问题留给实现TCP的编程人员去处理。他们有两个基本的选择 接收方立即丢弃失序报文段如前所述这可以简化接收方的设计接收方保留失序的字节并等待缺少的字节以填补该间隔。 显然后一种选择对网络带宽而言更为有效是实践中采用的方法。 TCP协议中关于初始序列号的选择也是有讲究的: 一条 TCP连接的双方均可随机地选择初始序号。这样做可以减少将那些仍在网络中存在的来自两台主机之间先前已终止的连接的报文段误认为是后来这两台主机之间新建连接所产生的有效报文段的可能性它碰巧与旧连接使用了相同的端口号。 关于TCP协议中的确认号我们也需要注意下面这点: TCP协议通常会将对客户到服务器的数据的确认装载在一个承载服务器到客户的数据的报文段中这种确认被称为是被捎带piggybacked在服务器到客户的数据报文段中的。同时如上图所示该报文段的确认号字段填入的是80因为客户已经收到了字节流中序号为79及以前的字节它现在正等待着字节80的出现。你可能认为这有点奇怪即使该报文段里没有数据还仍有序号。这是因为TCP存在序号字段报文段需要填入某个序号。 下面我们再来看看TCP中隐式NAK的实现: TCP通过使用肯定确认与定时器来提供可靠数据传输。TCP确认正确接收到的数据而当认为报文段或其确认报文丢失或受损时TCP会重传这些报文段。有些版本的TCP还有一个隐式NAK机制在TCP的快速重传机制下收到对一个特定报文段的3个冗余ACK就可作为对后面报文段的一个隐式NAK从而在超时之前触发对该报文段的重传。TCP使用序号以使接收方能识别丢失或重复的报文段由于TCP自己也无法明确地分辨一个报文段或其ACK是丢失了还是受损了或是时延过长了。所以在发送方TCP的响应是相同的重传有疑问的报文段。 最后我们再来看看关于TCP中流水线的说明: TCP也使用流水线使得发送方在任意时刻都可以有多个已发出但还未被确认的报文段存在。当报文段长度与往返时延之比很小时流水线可显著地增加一个会话的吞吐量。一个发送方能够具有的未被确认报文段的具体数量是由TCP的流量控制和拥塞控制机制决定的。 可靠数据传输 由于运输层报文段是被IP数据报携带着在网络中传输的并且网络层服务是不可靠的所以需要像TCP这样的可靠传输协议来提供一种可靠数据传输服务。 本节我们来看看TCP是如何使用我们上一节讲到的可靠传输技术来实现可靠的数据传输协议的。 首先是TCP发送方其有3个与发送和重传有关的主要事件: 从上层应用程序接收数据将数据封装在一个报文段中并把该报文段交给IP层。每个报文段都包含一个序号这个序号就是该报文段第一个数据字节的字节流编号。并且此时如果定时器没有为其他报文段而运行则当报文段被传递给IP时TCP就启动该定时器。 这里注意: 为每一个已经发送但未被确认的报文段都与一个定时器相关联概念上是最简单的但是定时器的管理却需要相当大的开销。因此一般仅使用单一的重传定时器。我们这里可以将定时器想象为与最早的未被确认的报文段相关联。 定时器超时 TCP 通过重传引起超时的报文段来响应超时事件然后TCP重启定时器收到ACK时 TCP 将 ACK 的值 y 与它的变量 SendBase 进行比较。TCP 状态变量 SendBase 是最早未被确认的字节的序号。(SendBase - 1 是指接收方已正确按序接收到的数据的最后一个字节的序号)。由于TCP本身采用累积确认所以y确认了字节编号在y之前的所有字节都已经收到。如果y SendBase 则该ACK是在确认一个或多个先前未被确认的报文段。因此发送方更新它的Sendbase变量如果当前有未被确认的报文段TCP还要重新启动定时器。 // 假设发送方不受TCP流量和拥塞控制的限制,来自上层数据的长度小于MSS,且数据传送只在一个方向进行 NextSeqNum InitialSeqNumber SendBase InitialSeqNumbderloop (永远) {switch (事件) 事件: 从上面应用程序接收到数据生成具有序号NextSeqNum的TCP报文段if (定时器当前没有运行)启动定时器向IP传递报文段NextSeqNum NextSeqNum len(data)break;事件: 定时器超时重传具有最小序号但仍未应答的报文段启动定时器break;事件: 收到ACK,具有ACK字段值yif(y SendBase){SendBasey;if (当前存在未应答报文段)启动定时器 }break; }关于TCP的可靠传输实现这里有四点需要我们注意。 避免重传 TCP实际采用了GBN混合ARQ的策略所以可以避免不必要的数据报重传如下面这三个例子所示: 例子1: 主机A向主机B发送一个报文段。假设该报文段的序号是92而且包含8字节数据。在发出该报文段之后主机A等待一个来自主机B的确认号为100的报文段。虽然A发出的报文段在主机B上被收到但从主机B发往主机A的确认报文丢失了。在这种情况下超时事件就会发生主机A会重传相同的报文段。当然当主机B收到该重传的报文段时它将通过序号发现该报文段包含了早已收到的数据。因此主机B中的TCP将丢弃该重传的报文段中的这些字节。 例子2: 在第二种情况中主机A连续发回了两个报文段。第一个报文段序号是92包含8字节数据第二个报文段序号是100包含20字节数据。假设两个报文段都完好无损地到达主机B并且主机B为每一个报文段分别发送一个确认。第一个确认报文的确认号是100第二个确认报文的确认号是120。现在假设在超时之前这两个报文段中没有一个确认报文到达主机A。当超时事件发生时主机A重传序号92的第一个报文段并重启定时器。只要第二个报文段的ACK在新的超时发生以前到达则第二个报文段将不会被重传。 例子3: 假设主机A与第二种情况中一样发送两个报文段。第一个报文段的确认报文在网络丢失但在超时事件发生之前主机A收到一个确认号为120的确认报文。主机A因而知道主机B已经收到了序号为119以及之前的所有字节所以主机A不会重传这两个报文段中的任何一个。 超时时间加倍 每当超时事件发生时TCP重传具有最小序号的还未被确认的报文段。只是每次TCP重传时都会将下一次的超时间隔设为先前值的两倍而不是用从EstimatedRTT和DevRTT推算出的值。 例如假设当定时器第一次过期时与最早的未被确认的报文段相关联的TimeoutInterval是0.75秒。TCP就会重传该 报文段并把新的过期时间设置为1.5秒。如果1.5秒后定时器又过期了则TCP将再次重传该报文段并把过期时间设置为3.0 秒。因此超时间隔在每次重传后会呈指数型增长。然而每当定时器在另两个事件即收到上层应用的数据和收到ACK中的任意一个启动时TimeoutInterval 由最近的EstimatedRTT值与DevRTT值推算得到相当于重置回默认值。 这种修改提供了一个形式受限的拥塞控制。定时器过期很可能是由网络拥塞引起的即太多的分组到达源与目的地之间路径上的一台或多台路由器的队列中造成分组丢失或长时间的排队时延。在拥塞的时候如果源持续重传分组会使拥塞更加严重。相反TCP使用更文雅的方式每个发送方的重传都是经过越来越长的时间间隔后进行的。 快速重传 超时触发重传存在的问题之一是超时周期可能相对较长。当一个报文段丢失时这种长超时周期迫使发送方延迟重传丢失的分组因而增加了端到端时延。 幸运的是发送方通常可在超时事件发生之前通过注意所谓冗余ACK来较好地检测到丢包情况。冗余ACKduplicate ACK就是再次确认某个报文段的ACK而发送方先前已经收到对该报文段的确认。要理解发送方对冗余ACK的响应我们必须首先看一下接收方为什么会发送冗余ACK。 下表总结了TCP接收方的ACK生成策略。当TCP接收方收到一个具有这样序号的报文段时即其序号大于下一个所期望的、按序的报文段它检测到了数据流中的一个间隔这就是说有报文段丢失。这个间隔可能是由于在网络中报文段丢失或重新排序造成的。因为TCP不使用否定确认所以接收方不能向发送方发回一个显式的否定确认。相反它只是对已经接收到的最后一个按序字节数据进行重复确认即产生一个冗余ACK即可。 下表中允许接收方不丢弃失序报文段实际的TCP协议栈实现过程中接收方也都会缓存失序到达的报文段而非直接丢弃这一点和ARQ协议做法一致。 因为发送方经常一个接一个地发送大量的报文段如果一个报文段丢失就很可能引起许多一个接一个的冗余ACK。如果TCP发送方接收到对相同数据的3个冗余ACK它把这当作一种指示说明跟在这个已被确认过3次的报文段之后的报文段已经丢失。一旦收到3个冗余ACKTCP就执行快速重传fast retransmit即 在该报文段的定时器过期之前重传丢失的报文段。 对于采用快速重传的TCP可用下面的伪代码进行表述: 事件: 收到ACK,具有ACK字段值yif ( y SendBase ) {SendBase y if (存在未应答的报文段)启动定时器 } else {// 对已经确认的报文段的一个冗余ACK对y收到的冗余ACK数加1if(y3)// TCP快速重传重新发送具有序号y的报文段} break; 回退N步还是选择重传 TCP是一个GBN协议还是一个SR协议前面讲过TCP确认是累积式的正确接收但失序的报文段是不会被接收方逐个确认的。 因此TCP发送方仅需维持已发送过但未被确认的字节的最小序号SendBase和下一个要发送的字节的序号NextSeqNum。在这种意义下TCP看起来更像一个GBN风格的协议。但是TCP和GBN 协议之间有着一些显著的区别。许多TCP实现会将正确接收但失序的报文段缓存起来。另外考虑一下当发送方发送的一组报文段12···N并且所有的报文段都按序无差错地到达接收方时会发生的情况。 进一步假设对分组 N 的确认报文丢失但是其余 N - 1 个确认报文在分别超时以前到达发送端这时又会发生情况。在该例中GBN不仅会重传分组n还会重传后面的分组n1n2… N 。而对于TCP来说其将重传至多一个报文段n。此外如果对报文段n1的确认报文在报文段n超时之前到达TCP压根就无需重传报文段n。 这一部分内容在避免重传一小节讲过不清楚可以回看。 对TCP提出的一种修改意见是所谓的 选择确认selective acknowledgment它允许TCP接收方有选择地确认失序报文段而不是累积地确认最后一个正确接收的有序报文段。当将该机制与选择重传机制结合起来使用时即跳过重传那些已被接收方选择性地确认过的报文段TCP看起来就很像我们通常的SR协议。因此TCP的差错恢复机制也许最好被分类为GBN协议与SR协议的混合体。 流量控制 前面讲过一条TCP连接的每一侧主机都为该连接设置了接收缓存。当该TCP连接收到正确、按序的字节后它就将数据放入接收缓存。相关联的应用进程会从该缓存中读取数据但不必是数据刚一到达就立即读取。事实上接收方应用也许正忙于其他任务甚至要过很长时间后才去读取该数据。如果某应用程序读取数据时相对缓慢而发送方发送得太多、太快发送的数据就会很容易地使该连接的接收缓存溢出。 TCP为它的应用程序提供了流量控制服务以消除发送方使接收方缓存溢出的可能性。流量控制因此是一个速度匹配服务即发送方的发送速率与接收方应用程序的读取速率相匹配。前面提到过TCP发送方也可能因为IP网络的拥塞而被遏制这种形式的发送方的控制被称为拥塞控制。 流量控制和拥塞控制采取的动作非常相似对发送方的遏制但是它们显然是针对完全不同的原因而采取的措施。现在我们来讨论TCP 如何提供流量控制服务的。为了能从整体上看问题我们在本节都假设TCP是这样实现的即TCP接收方丢弃失序的报文段。 TCP通过让发送方维护一个称为接收窗口receive window的变量来提供流量控制。通俗地说接收窗口用于给发送方一个指示—该接收方还有多少可用的缓存空间。因为TCP是全双工通信在连接两端的发送方都各自维护一个接收窗口。 假设主机A通过一条TCP连接向主机B发送一个大文件。主机B为该连接分配了一个接收缓存并用RcvBuffer来表示其大小。主机B上的应用进程不时地从该缓存中读取数据。我们定义以下变量 LastByteRead主机B上的应用进程从缓存读出的数据流的最后一个字节的编号。LastByteRcvd从网络中到达的并且已放入主机B接收缓存中的数据流的最后一个字节的编号。 由于TCP不允许已分配的缓存溢出下式必须成立 LastByteRcvd - LastByteRead ≤ RcvBuffer 接收窗口用rwnd表示根据缓存可用空间的数量来设置 rwnd RevBuffer - [ LastByteRcvd - LastByteRead ] 由于该空间是随着时间变化的所以rwnd是动态的。 连接是如何使用变量rwnd 来提供流量控制服务的呢 主机B通过把当前的rwnd值放入它发给主机A的报文段接收窗口字段中通知主机A它在该连接的缓存中还有多少可用空间。开始时主机B设定 rwndRcvBuffer。注意到为了实现这 一点主机B必须跟踪几个与连接有关的变量。 主机A轮流跟踪两个变量LastByteSent 和LastByteAcked这两个变量的意义很明显。 注意到这两个变量之间的差LastByteSent - LastByteAcked就是主机A发送到连接中但未 被确认的数据量。通过将未确认的数据量控制在值rwnd以内就可以保证主机A不会使主机B的接收缓存溢出。因此主机A在该连接的整个生命周期须保证 LastByteSent - LastByteAcked ≤ rwnd 对于这个方案还存在一个小小的技术问题。为了理解这一点假设主机B的接收缓存已经存满使得rwnd0。在将rwnd0通告给主机A之后还要假设主机B没有任何数据要发给主机A。此时考虑会发生什么情况 因为主机B上的应用进程将缓存清空TCP并不向主机A发送带有rwnd新值的新报文段事实上TCP仅当在它有数据或有确认要发时才会发送报文段给主机A。这样主机A不可能知道主机B的接收缓存已经有新的空间了即主机A被阻塞而不能再发送数据为了解决这个问题TCP规范中要求当主机B的接收窗口为0时主机A继续发送只有一个字节数据的报文段。这些报文段将会被接收方确认。最终缓存将开始清空并且确认报文里将包含一个非0的rwnd值。 描述了TCP的流量控制服务以后我们在此要简要地提一下UDP并不提供流量控制报文段由于缓存溢出可能在接收方丢失。 例如考虑一下从主机A上的一个进程向主机B上的一个进程发送一系列UDP报文段的情形。对于一个典型的UDP实现UDP将在一个有限大小的缓存中加上报文段该缓存在相应套接字进程的门户“之前”。进程每次从缓存中读取一个完整的报文段。如果进程从缓存中读取报文段的速度不够快那么缓存将会溢出并且将丢失报文段。 连接管理 在本节中我们来看看如何建立和拆除一条TCP连接。假设运行在一台主机客户上的一个进程想与另一台主机服务器上的一个进程建立一条连接。客户应用进程首先通知客户TCP它想建立一个与服务器上某个进程之间的连接。客户中的TCP会用以下方式与服务器中的TCP建立一条TCP连接 客户端的TCP首先向服务器端的TCP发送一个特殊的TCP报文段。该报文段中不包含应用层数据。但是在报文段的首部中的一个标志位即SYN比特被置为1。因此这个特殊报文段被称为SYN报文段。另外客户会随机地选择一个初始序号clientisn并将此编号放置于该起始的TCP SYN报文段的序号字段中。该报文段会被封装在一个IP数据报中并发送给服务器。为了避免某些安全性攻击在适当地随机化选择clientisn方面有着不少有趣的研究。一旦包含TCP SYN报文段的IP数据报到达服务器主机服务器会从该数据报中提取出TCP SYN报文段为该TCP连接分配TCP缓存和变量并向该客户TCP发送允许连接的报文段。这个允许连接的报文段也不包含应用层数据。但是在报文段的首部却包含3个重要的信息。首先SYN比特被置为1。其次该TCP报文段首部的确认号字段被置为clientisn1。最后服务器选择自己的初始序号serverisn并将其放置到TCP报文段首部的序号字段中。这个允许连接的报文段实际上表明了“我收到了你发起建立连接的SYN分组该分组带有初始序号clientisn。我同意建立该连接。我自己的初始序号是serverisn。”该允许连接的报文段被称为SYN - ACK报文段。在收到SYN - ACK报文段后客户也要给该连接分配缓存和变量。客户主机则向服务器发送另外一个报文段这最后一个报文段对服务器的允许连接的报文段进行了确认该客户通过将值 serverisn1放置到TCP报文段首部的确认字段中来完成此项工作。因为连接已经建立了所以该SYN比特被置为0。该三次握手的第三个阶段可以在报文段负载中携带客户到服务器的数据。 一旦完成这3个步骤客户和服务器主机就可以相互发送包括数据的报文段了。在以后每一个报文段中SYN比特都将被置为0。注意到为了创建该连接在两台主机之间发送了3个分组。由于这个原因这种连接创建过程通常被称为3次握手。 参与TCP连接的两个进程中任何一个都能终止该连接。当连接结束后主机中的“资源”即缓存和变量将被释放。假设某客户打算关闭连接 客户应用进程发出一个关闭连接命令。这会引起客户TCP向服务器进程发送一个特殊的TCP报文段。这个特殊的报文段让其首部中的一个标志位即FIN比特被设置为1。当服务器接收到该报文段后就向发送方回送一个确认报文段。然后服务器发送它自己的终止报文段其FIN比特被置为1。最后该客户对这个服务器的终止报文段进行确认。此时在两台主机上用于该连接的所有资源都被释放了。 在一个TCP连接的生命周期内运行在每台主机中的TCP协议在各种TCP状态TCP state之间变迁。下图说明了客户TCP会经历的一系列典型TCP状态: 客户TCP开始时处于CLOSED关闭状态。客户的应用程序发起一个新的TCP连接。这引起客户中的TCP向服务器中的TCP发送一个SYN报文段。在发送过SYN报文段后客户TCP进入了SYNSENT状态。当客户TCP处在SYNSENT状态时它等待来自服务器TCP的对客户所发报文段进行确认且SYN比特被置为1的一个报文段。收到这样一个报文段之后客户TCP进入ESTABLISHED已建立状态。当处在ESTABLISHED状态时TCP客户就能发送和接收包含有效载荷数据即应用层产生的数据的TCP报文段了。假设客户应用程序决定要关闭该连接。注意到服务器也能选择关闭该连接。这引起客户TCP发送一个带有FIN比特被置为1的TCP报文段并进入FINWAIT1状态。当处在FINWAIT1状态时客户TCP等待一个来自服务器的带有确认的TCP报文段。当它收到该报文段时客户TCP进入FINWAIT2状态。当处在FINWAIT2状态时客户等待来自服务器的FIN比特被置为1的另一个报文段当收到该报文段后客户TCP对服务器的报文段进行确认并进入TIMEWAIT状态。假定ACK丢失TIMEWAIT状态使TCP 客户重传最后的确认报文。在TIMEWAIT状态中所消耗的时间是与具体实现有关的而典型的值是30秒、1分钟或2分钟。经过等待后连接就正式关闭客户端所有资源包括端口号将被释放。 上面我们站在客户端的视角看了整个TCP状态转换图下面我们站在服务器端的视角来看看TCP状态转换过程: 初始时服务器正在监听客户发送其SYN报文段的端口。我们来考虑当一台主机接收到一个TCP报文段其端口号或源IP地址与该主机上进行中的套接字都不匹配的情况。 例如假如一台主机接收了具有目的端口80的一个TCP SYN分组但该主机在端口80不接受连接即它不在端口80上运行Web服务器。则该主机将向源发送一个特殊重置报文段。该TCP报文段将RST标志位置为1。因此当主机发送一个重置报文段时它告诉该源“我没有那个报文段的套接字。请不要再发送该报文段了”。当一台主机接收一个UDP分组它的目的端口与进行中的UDP套接字不匹配该主机发送一个特殊的ICMP数据报。 下面再来简单介绍一下nmap端口扫描工具的实现原理: 为了探索目标主机上的一个特定的TCP端口如端口6789nmap将对那台主机的目的端口6789发送一个特殊的TCP SYN报文段。有3种可能的输出 源主机从目标主机接收到一个TCP SYN - ACK报文段。因为这意味着在目标主机上一个应用程序使用TCP端口6789运行nmap返回“打开”。源主机从目标主机接收到一个TCP RST报文段。这意味着该SYN报文段到达了目标主机但目标主机没有运行一个使用TCP端口6789的应用程序。但攻击者至少知道发向该主机端口6789的报文段没有被源和目标主机之间的任何防火墙所阻挡。源什么也没有收到。这很可能表明该SYN报文段被中间的防火墙所阻挡无法到达目标主机。 拥塞控制 在前面几节中我们已经分析了面临分组丢失时用于提供可靠数据传输服务的基本原理及特定的TCP机制。我们以前讲过在实践中这种丢包一般是当网络变得拥塞时由于路由器缓存溢出引起的。分组重传因此作为网络拥塞的征兆某个特定的运输层报文段的丢失来对待但是却无法处理导致网络拥塞的原因因为有太多的源想以过高的速率发送数据。为了处理网络拥塞原因需要一些机制以在面临网络拥塞时遏制发送方。 拥塞原因 这里以书上三个循序渐进的例子为例进行说明: 两个发送方和一台具有无穷大缓存的路由器 随着分组的到达速率接近链路容量时分组会经历巨大的排队时延。 两个发送方和一台具有有限缓存的路由器 随着分组的到达速率接近链路容量时发送方必须执行重传来补偿因为缓存溢出而丢弃的分组。但是这样做又可能在发送方遇到大时延时进行不必要的重传从而加剧传输链路本身的拥塞程度因为链路上的路由器需要转发不必要的分组副本。 四个发送方和具有有限缓存的多台路由器以及多跳路径 当一个分组沿一条路径被丢弃时每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量最终都会被浪费掉。 拥塞控制方法 关于拥塞控制的方法可以根据网络层是否为运输层拥塞控制提供显式帮助来区分拥塞控制方法: 端到端拥塞控制。在端到端拥塞控制方法中网络层没有为运输层拥塞控制提供显式支持。即使网络中存在拥塞端系统也必须通过对网络行为的观察如分组丢失与时延来推断之。 TCP采用端到端的方法解决拥塞控制因为IP层不会向端系统提供有关网络拥塞的反馈信息。TCP报文段的丢失通过超时或3次冗余确认而得知被认为是网络拥塞的一个迹象TCP会相应地减小其窗口长度。我们还将看到关于TCP拥塞控制的一些最新建议即使用增加的往返时延值作为网络拥塞程度增加的指示。 网络辅助的拥塞控制。在网络辅助的拥塞控制中路由器向发送方提供关于网络中拥塞状态的显式反馈信息。这种反馈可以简单地用一个比特来指示链路中的拥塞情况。该方法在早期的IBM SNASchwartz 1982、DEC DECnet Jain 1989 Ramakrishnan 1990 和ATM Black 1995等体系结构中被采用。更复杂的网络 反馈也是可能的。 例如在ATM可用比特率Available Bite RateABR拥塞控制中路由器显式地通知发送方它路由器能在输出链路上支持的最大主机发送速率。如上面所提到的默认因特网版本的IP和TCP采用端到端拥塞控制方法。然而IP和TCP也能够选择性地实现网络辅助拥塞控制。 对于网络辅助的拥塞控制拥塞信息从网络反馈到发送方通常有以下两种方式 直接反馈信息可以由网络路由器发给发送方。这种方式的通知通常采用了一种阻塞分组choke packet的形式主要是说“我拥塞了”。更为通用的第二种形式的通知是路由器标记或更新从发送方流向接收方的分组中的某个字段来指示拥塞的产生。一旦收到一个标记的分组后接收方就会向发送方通知该网络拥塞指示。注意到后一种形式的通知至少要经过一个完整的往返时间。 端到端拥塞控制 上一节说过TCP必须使用端到端拥塞控制而不是使网络辅助的拥塞控制因为IP层不向端系统提供显式的网络拥塞反馈。 TCP所采用的方法是让每一个发送方根据所感知到的网络拥塞程度来限制其能向连接发送流量的速率。如果一个TCP发送方感知从它到目的地之间的路径上没什么拥塞则TCP发送方增加其发送速率如果发送方感知沿着该路径有拥塞则发送方就会降低其发送速率。但是这种方法提出了三个问题。第一一个TCP发送方如何限制它向其连接发送流量的速率呢第二一个TCP发送方如何感知从它到目的地之间的路径上存在拥塞呢第三当发送方感知到端到端的拥塞时采用何种算法来改变其发送速率呢 如何限制发送速率 我们首先分析一下TCP发送方是如何限制向其连接发送流量的。之前说过TCP连接的每一端都是由一个接收缓存、一个发送缓存和几个变量LastByteRead、rwnd等组成。运行在发送方的TCP拥塞控制机制跟踪一个额外的变量即拥塞窗口congestion window。拥塞窗口表示为cwnd它对一个TCP发送方能向网络中发送流量的速率进行了限制。特别是在一个发送方中未被确认的数据量不会超过cwnd与rwnd中的最小值即 LastByteSent - LastByteAcked ≤ min | cwnd,rwnd | 为了关注拥塞控制与流量控制形成对比我们后面假设TCP接收缓存足够大以至可以忽略接收窗口的限制因此在发送方中未被确认的数据量仅受限于cwnd。我们还假设发送方总是有数据要发送即在拥塞窗口中的所有报文段要被发送。 上面的约束限制了发送方中未被确认的数据量因此间接地限制了发送方的发送速率。为了理解这一点我们来考虑一个丢包和发送时延均可以忽略不计的连接。因此粗略地讲在每个往返时间RTT的起始点上面的限制条件允许发送方向该连接发送cwnd个字节的数据在该RTT结束时发送方接收对数据的确认报文。因此该发送方的发送速率大概是cwndRTT字节秒。通过调节 cwnd的值发送方因此能调整它向连接发送数据的速率。 如何感知拥塞 我们接下来考虑 TCP发送方是如何感知在它与目的地之间的路径上出现了拥塞的。我们将一个TCP发送方的“丢包事件”定义为要么出现超时要么收到来自接收方的3个冗余ACK。 当出现过度的拥塞时在沿着这条路径上的一台或多台路由器的缓存会溢出引起一个数据报包含一个 TCP报文段被丢弃。丢弃的数据报接着会引起发送方的丢包事件要么超时或收到3个冗余ACK发送方就认为在发送方到接收方的路径上出现了拥塞的指示。 考虑了拥塞检测问题后我们接下来考虑网络没有拥塞这种更为乐观的情况即没有出现丢包事件的情况。在此情况下在TCP的发送方将收到对于以前未确认报文段的确认。如我们将看到的那样TCP将这些确认的到达作为一切正常的指示即在网络上传输的报文段正被成功地交付给目的地并使用确认来增加拥塞窗口的长度及其传输速率。 注意到如果确认以相当慢的速率到达例如如果该端到端路径具有高时延或包含一段低带宽链路则该拥塞窗口将以相当慢的速率增加。在另一方面如果确认以高速率到达则该拥塞窗口将会更为迅速地增大。因为TCP使用确认来触发或计时增大它的拥塞窗口长度TCP被说成是自计时self-clocking的。 给定调节cwnd值以控制发送速率的机制关键的问题依然存在TCP发送方怎样确定它应当发送的速率呢如果众多TCP发送方总体上发送太快它们能够拥塞网络进一步导致网络拥塞加剧。 TCP使用下列指导性原则回答这些问题 一个丢失的报文段表意味着拥塞因此当丢失报文段时应当降低TCP发送方的速率。对于给定报文段一个超时事件或四个确认一个初始ACK和其后的三个冗余ACK被解释为跟随该四个ACK的报文段的“丢包事件”的一种隐含的指示。从拥塞控制的观点看该问题是TCP发送方应当如何减小它的拥塞窗口长度即减小其发送速率以应对这种推测的丢包事件。一个确认报文段指示该网络正在向接收方交付发送方的报文段因此当对先前未确认报文段的确认到达时能够增加发送方的速率。确认的到达被认为是一切顺利的隐含指示即报文段正从发送方成功地交付给接收方因此该网络不拥塞。拥塞窗口长度因此能够增加。带宽探测。给定ACK指示源到目的地路径无拥塞而丢包事件指示路径拥塞TCP调节其传输速率的策略是增加其速率以响应到达的ACK除非出现丢包事件此时才减小传输速率。因此为探测拥塞开始出现的速率TCP发送方增加它的传输速率从该速率后退进而再次开始探测看看拥塞开始速率是否发生了变化。 TCP发送方的行为也许类似于要求并得到越来越多糖果的孩子直到最后告知他她“不行”孩子后退一点然后过一会儿再次开始提出请求。注意到网络中没有明确的拥塞状态信令即ACK和丢包事件充当了隐式信号并且每个TCP发送方根据异步于其他TCP发送方的本地信息而行动。 拥塞控制算法 本节我们来看看广受赞誉的TCP拥塞控制算法该算法包括3个部分: 慢启动拥塞避免和快速恢复。 慢启动和拥塞避免时TCP的强制部分两者的差异在于对收到的ACK做出反应时增加cwnd长度的方式。同时慢启动比拥塞避免能更快地增加cwnd的长度。快速恢复是推荐部分并非是必需的。 慢启动 当一条TCP连接开始时cwnd的值通常初始为一个MSS的较小值这就使得初始发送速率大约为MSS/RTT。由于对TCP发送方而言可用带宽可能比MSS/RTT大得多TCP发送方希望迅速找到可用带宽的数量。因此在慢启动状态cwnd的值以1个MSS开始并且每当传输的报文段首次被确认就增加1个MSS。 在上图所示的例子中TCP向网络发送第一个报文段并等待一个确认。当该确认到达时TCP发送方将拥塞窗口增加一个MSS并发送出两个最大长度的报文段。这两个报文段被确认则发送方对每个确认报文段将拥塞窗口增加一个MSS使得拥塞窗口变为4个MSS并这样下去。这一过程每过一个RTT发送速率就翻番。因此TCP发送速率起始慢但在慢启动阶段以指数增长。 但是何时结束这种指数增长呢慢启动对这个问题提供了几种答案 首先如果存在一个由超时指示的丢包事件即拥塞TCP发送方将cwnd设置为1MSS并重新开始慢启动过程。它还将第二个状态变量的值ssthresh“慢启动阈值”的速记设置为 cwnd/2即当检测到拥塞时将 ssthresh 置为拥塞窗口值的一半。慢启动结束的第二种方式是直接与ssthresh的值相关联。因为当检测到拥塞时 ssthresh 设为 cwnd 的值一半当到达或超过ssthresh的值时继续使 cwnd 翻番可能有些鲁莽。因此当 cwnd的值等于ssthresh时结束慢启动并且TCP转移到拥塞避免模式。我们将会看到当进入拥塞避免模式时TCP更为谨慎地增加cwnd。最后一种结束慢启动的方式是如果检测到 3 个冗余 ACK这时 TCP 执行一种快速重传并进入快速恢复状态后面将讨论相关内容。 ssthresh 是慢启动阈值当拥塞窗口大小大于等于该值时会从慢启动状态转变为拥塞避免状态当拥塞窗口大小小于该值时会从拥塞避免状态转变为慢启动状态。 拥塞避免 一旦进入拥塞避免状态cwnd的值大约是上次遇到拥塞时的值的一半即距离拥塞可能并不遥远因此TCP无法每过一个RTT再将cwnd的值翻番而是采用了一种较为保守的方法每个RTT只将cwnd的值增加一个MSS。这能够以几种方式完成。一种通用的方法是对于TCP发送方无论何时到达一个新的确认就将cwnd增加一个MSSMSScwnd字节。 例如如果MSS是1460字节并且cwnd是14600字节则在一个RTT内发送10个报文段。每个到达ACK假定每个报文段一个ACK增加1/10 * MSS的拥塞窗口长度因此在收到对所有10个报文段的确认后拥塞窗口的值将增加了一个MSS。 但是何时应当结束拥塞避免的线性增长每RTT 1MSS呢 当出现超时时TCP的拥塞避免算法行为相同。与慢启动的情况一样cwnd的值被设置为1个MSS当丢包事件出现时ssthresh的值被更新为cwnd值的一半。然而前面讲过丢包事件也能由一个三个冗余ACK事件触发。在这种情况下网络继续从发送方向接收方交付报文段就像由收到冗余ACK所指示的那样。因此TCP对这种丢包事件的行为相比于超时指示的丢包应当不那么剧烈TCP将cwnd的值减半为使测量结果更好对于已收到的3个冗余的ACK要加上3个MSS并且当收到3个冗余的ACK将ssthresh的值记录为cwnd的值的一半。接下来进入快速恢复状态。 快速恢复 在快速恢复中对于引起TCP进入快速恢复状态的缺失报文段对收到的每个冗余的ACKcwnd的值增加一个MSS。最终当对丢失报文段的一个ACK到达时TCP在降低cwnd后进入拥塞避免状态。如果出现超时事件快速恢复在执行如同在慢启动和拥塞避免中相同的动作后迁移到慢启动状态当丢包事件出现时cwnd的值被设置为1个MSS并且ssthresh的值设置为cwnd值的一半。 快速恢复是TCP推荐的而非必需的构件。有趣的是一种称为TCP Tahoe的TCP早期版本不管是发生超时指示的丢包事件还是发生3个冗余ACK指示的丢包事件都无条件地将其拥塞窗口减至1个MSS并进入慢启动阶段。TCP的较新版本TCP Reno则综合了快速恢复。 下图展示了Reno 版TCP 和 Tahoe 版TCP 的拥塞控制窗口演化情况。在该图中初始阈值等于8个MSS在前8个传输回合Tahoe 和 Reno 都采取了相同的动作。 拥塞窗口在慢启动阶段以指数速度快速爬升在第4轮传输时到达了阈值(慢启动阶段)。然后拥塞窗口以线性速度爬升(拥塞避免阶段)直到在第8轮传输后出现3个冗余ACK。注意到当该丢包事件发生时拥塞窗口值为12xMSS。于是ssthresh的值被设置为0.5xcwnd6x MSS。在TCP Reno下拥塞窗口被设置 为cwnd9MSS然后线性地增长(快速恢复阶段)。在TCP Tahoe 下拥塞窗口被设置为1个MSS然后呈指数增长直至到达 ssthresh (慢启动阶段)。 小结 在深入了解慢启动、拥塞避免和快速恢复的细节后现在有必要退回来回顾一下全局。忽略一条连接开始时初始的慢启动阶段假定丢包由3个冗余的ACK而不是超时指示TCP的拥塞控制是每个RTT内cwnd线性加性增加1MSS然后出现3个冗余ACK事件时cwnd减半乘性减。因此TCP拥塞控制常常被称为加性增、乘性减Additive-Increase Multiplicative-DecreaseAIMD拥塞控制方式。AIMD拥塞控制引发了下图中所示的“锯齿”行为这也很好地图示了我们前面TCP检测带宽时的直觉即TCP线性地增加它的拥塞窗口长度因此增加其传输速率直到出现3个冗余ACK事件。然后以2个因子来减少它的拥塞窗口长度然后又开始了线性增长探测是否还有另外的可用带宽。 许多TCP实现采用了Reno算法同时也存在很多Reno算法的变种比如TCP Vegas算法该算法试图在维持较好的吞吐量的同时避免阻塞。 该算法基本思想是: 在分组丢失发生之前在源目的地与目的地之间检测路由器中的拥塞当检测出快要发生的分组丢失时线性地降低发送速率。 快要发生分组丢失是通过观察RTT来预测的分组的RTT越长路由器中的拥塞越严重。 最后贴出一张慢启动拥塞避免快速恢复三个状态的转换图: 初始状态为慢启动拥塞窗口翻倍增长当窗口大小大于等于ssthresh阈值时进入拥塞避免状态。当出现三次冗余ACK时进入快速恢复状态。出现超时或者接收到新的ACK情况还是保持慢启动状态不变。拥塞避免状态下如果发生超时丢包则退回慢启动状态。如果出现三次冗余ACK则转变为快速恢复状态。快速恢复状态下如果发生超时丢包则退回慢启动状态。如果接受到新的ACK则转变为拥塞避免状态。 拥塞窗口阈值大小和拥塞窗口大小的变化可以参考上图学习这里就不再赘述。 公平性 考虑K条TCP连接每条都有不同的端到端路径但是都经过一段传输速率为R bps的瓶颈链路。所谓瓶颈链路是指对于每条连接沿着该连接路径上的所有其他段链路都不拥塞而且与该瓶颈链路的传输容量相比它们都有充足的传输容量。假设每条连接都在传输一个大文件而且无 UDP 流量通过该段瓶颈链路。如果每条连接的平均传输速率接近R/K即每条连接都得到相同份额的链路带宽则认为该拥塞控制机制是公平的。 TCP的AIMD算法公平吗尤其是假定可在不同时间启动并因此在某个给定的时间点可能具有不同的窗口长度情况下对这些不同的TCP连接还是公平的吗TCP趋于在竞争的多条TCP连接之间提供对一段瓶颈链路带宽的平等分享。 我们考虑有两条TCP连接共享一段传输速率为R的链路的简单例子如下图所示: 我们将假设这两条连接有相同的MSS和RTT这样如果它们有相同的拥塞窗口长度就会有相同的吞吐量它们有大量的数据要发送且没有其他TCP连接或UDP数据报穿越该段共享链路。我们还将忽略TCP的慢启动阶段并假设TCP连接一直按CA模式AIMD运行。 上图描绘了两条TCP连接实现的吞吐量情况。如果TCP要在这两条TCP连接之间平等地共享链路带宽那么实现的吞吐量曲线应当是从原点沿45°方向的箭头向外辐射平等带宽共享。理想情况是两个吞吐量的和应等于R。当然每条连接得到相同但容量为0的共享链路容量并非我们所期望的情况所以我们的目标应该是使取得的吞吐量落在图中平等带宽共享曲线与全带宽利用曲线的交叉点附近的某处。 假定TCP窗口长度是这样的即在某给定时刻连接1和连接2实现了由上图中A点所指明的吞吐量。因为这两条连接共同消耗的链路带宽量小于R所以无丢包事件发生根据TCP的拥塞避免算法的结果这两条连接每过一个RTT都要将其窗口增加1个MSS。因此这两条连接的总吞吐量就会从A点开始沿45°线前行两条连接都有相同的增长。最终这两条连接共同消耗的带宽将超过R最终将发生分组丢失。 假设连接1和连接2实现B点指明的吞吐量时它们都经历了分组丢失。连接1和连接2于是就按二分之一减小其窗口。所产生的结果实现了C点指明的吞吐量它正好位于始于B点止于原点的一个向量的中间。因为在C点共同消耗的带宽小于R所以这两条连接再次沿着始于C点的45°线增加其吞吐量。最终再次发生丢包事件如在D点这两条连接再次将其窗口长度减半如此等等。你应当搞清楚这两条连接实现的带宽最终将沿着平等带宽共享曲线在波动。还应该搞清楚无论这两条连接位于二维空间的何处它们最终都会收敛到该状态虽然此时我们做了许多理想化的假设但是它仍然能对解释为什么TCP会导致在多条连接之间的平等共享带宽这个问题提供一个直观的感觉。 在理想化情形中我们假设仅有TCP连接穿过瓶颈链路所有的连接具有相同的RTT值且对于一个主机—目的地对而言只有一条TCP连接与之相关联。实践中这些条件通常是得不到满足的客户—服务器应用因此能获得非常不平等的链路带宽份额。特别是已经表明当多条连接共享一个共同的瓶颈链路时那些具有较小RTT的连接能够在链路空闲时更快地抢到可用带宽即较快地打开其拥塞窗口因而将比那些具有较大RTT的连接享用更高的吞吐量。 自私自利的UDP 我们刚才已经看到TCP拥塞控制是如何通过拥塞窗口机制来调节一个应用程序的传输速率的。许多多媒体应用如因特网电话和视频会议经常就因为这种特定原因而不在TCP上运行因为它们不想其传输速率被扼制即使在网络非常拥塞的情况下。 相反这些应用宁可在UDP上运行UDP是没有内置的拥塞控制的。当运行在UDP上时这些应用能够以恒定的速率将其音频和视频数据注入网络之中并且偶尔会丢失分组而不愿在拥塞时将其发送速率降至“公平”级别并且不丢失任何分组。 从TCP的观点来看运行在UDP上的多媒体应用是不公平的因为它们不与其他连接合作也不适时地调整其传输速率。因为TCP拥塞控制在面临拥塞增加丢包时将降低其传输速率而UDP源则不必这样做UDP源有可能压制TCP流量。当今的一个主要研究领域就是开发一种因特网中的拥塞控制机制用于阻止UDP流量不断压制直至中断因特网吞吐量的情况。 并行TCP连接 即使我们能够迫使UDP流量具有公平的行为但公平性问题仍然没有完全解决。这是因为我们没有什么办法阻止基于TCP的应用使用多个并行连接。例如Web浏览器通常使用多个并行TCP连接来传送一个Web页中的多个对象。多条连接的确切数目可以在多数浏览器中进行配置。当一个应用使用多条并行连接时它占用了一条拥塞链路中较大比例的带宽。举例来说考虑一段速率为R且支持9个在线客户—服务器应用的链路每个应用使用一条TCP连接。如果一个新的应用加入进来也使用一条TCP连接则每个应用得到差不多相同的传输速率R10。但是如果这个新的应用这次使用了11个并行TCP连接则这个新应用就不公平地分到超过R2的带宽。Web流量在因特网中是非常普遍的所以多条并行连接并非不常见。 网络辅助拥塞控制 自20世纪80年代后期慢启动和拥塞避免开始标准化以来TCP已经实现了端到端拥塞控制的形式即一个TCP发送方不会收到来自网络层的明确拥塞指示而是通过观察分组丢失来推断拥塞。 对于IP和TCP的扩展方案也已经提出并已经实现和部署该方案允许网络明确向TCP发送方和接收方发出拥塞信号。这种形式的网络辅助拥塞控制称为明确拥塞通告ExplicitCongestion NotificationECN。 在网络层IP数据报首部的服务类型字段中的两个比特总的说来有四种可能的值被用于ECN。 路由器所使用的一种ECN比特设置指示该路由器正在历经拥塞。该拥塞指示则由被标记的IP数据报所携带送给目的主机再由目的主机通知发送主机如上图所示。RFC3168没有提供路由器拥塞时的定义该判断是由路由器厂商所做的配置选择并且由网络操作员决定。然而RFC3168推荐仅当拥塞持续不断存在时才设置ECN比特。发送主机所使用的另一种ECN比特设置通知路由器发送方和接收方是ECN使能的因此能够对于ECN指示的网络拥塞采取行动。 如上图所示当接收主机中的TCP通过一个接收到的数据报收到了一个ECN拥塞指示时接收主机中的TCP通过在接收方到发送方的TCP ACK报文段中设置ECE明确拥塞通告回显比特通知发送主机中的TCP收到拥塞指示。接下来TCP发送方通过减半拥塞窗口对一个具有ECE拥塞指示的ACK做出反应就像它对丢失报文段使用快速重传做出反应一样并且在下一个传输的TCP发送方到接收方的报文段首部中对CWR拥塞窗口缩减比特进行设置。 除了TCP以外的其他运输层协议也可以利用网络层发送ECN信号。数据报拥塞控制协议Datagram Congestion Control ProtocolDCCPRFC 4340提供了一种低开销、控制 拥塞的类似UDP不可靠服务该协议利用了ECN。DCTCP数据中心TCPAlizadeh 2010是一种专门为数据中心网络设计的TCP版本也利用了ECN。 小结 运输层协议能够提供可靠数据传输即使下面的网络层是不可靠的。我们也看到了提供可靠的数据传送会遇到许多微妙的问题但都可以通过精心地结合确认、定时器、重传以及序号机制来完成任务。 本文也详细地研究了TCP协议它是因特网中面向连接和可靠的运输层协议。我们知道TCP是非常复杂的它涉及了连接管理、流量控制、往返时间估计以及可靠数据传送。事实上TCP比我们描述的要更为复杂即我们有意地避而不谈在各种TCP实现版本中广泛实现的各种TCP补丁、修复和改进。然而所有这些复杂性都对网络层应用隐藏了起来。如果某主机上的客户希望向另一台主机上的服务器可靠地发送数据它只需要打开对该服务器的一个TCP套接字然后将数据注人该套接字。客户—服务器应用程序则乐于对TCP的复杂性视而不见。 最后我们从广泛的角度研究了拥塞控制我们知道了拥塞控制对于网络良好运行是必不可少的。没有拥塞控制网络很容易出现死锁使得端到端之间很少或没有数据能被传输。在本文中我们学习了TCP实现的一种端到端拥塞控制机制即当TCP连接的路径上判断不拥塞时其传输速率就加性增当出现丢包时传输速率就乘性减。这种机制也致力于做到每一个通过拥塞链路的TCP连接能平等地共享该链路带宽。我们也深入探讨了TCP连接建立和慢启动对时延的影响。我们观察到在许多重要场合连接建立和慢启动会对端到端时延产生严重影响。 最后我们再来看看其他的一些有趣协议: 数据报拥塞控制协议Datagram Congestion Control ProtocolDCCPRFC 4340提供 了一种低开销、面向报文类似于UDP的不可靠服务但是具有应用程序可选择的拥塞控制形式该机制与TCP相兼容。如果某应用程序需要可靠的或半可靠的数据传送则这将在应用程序自身中执行。DCCP被设想用于诸如流媒体等应用程序中DCCP能够利用数据交付的预定时间和可靠性之间的折中但是要对网络拥塞做出响应。在谷歌的Chromium 浏览器中实现了QUICQuick UDP Intemnet Connections协议 lyengar 2016该协议通过重传以及差错检测、快速连接建立和基于速率的拥塞控制算法提供可靠性而基于速率的拥塞控制算法是以TCP友好特性为目标这些机制都是在UDP之上作为应用层协议实现的。2015年年初谷歌报告从Chrome浏览器到谷歌服务器的大约一半请求运行在QUIC之上。DCTCP数据中心TCPAlizadeh 2010是一种专门为数据中心网络设计的TCP版本使用ECN以更好地支持短流和长流的混合流这种混合流代表了数据中心负载的特征。流控制传输协议Stream Control Transmission ProtocolSCTPRFC 4960RFC 3286 是一种可靠的、面向报文的协议该协议允许几个不同的应用层次的“流”复用到单个SCTP连接上一种称之为“多流”的方法。从可靠性的角度看在该连接中的不同流被分别处理因此在一条流中的分组丢失不会影响其他流中数据的交付。当一台主机与两个或更多个网络连接时SCTP也允许数据经两条出路径传输还具有失序数据的选项交付和一些其他特色。SCTP的流控制和拥塞控制算法基本上与TCP中的相同。TCP友好速率控制TCP-Friendly Rate ControlTFRC协议RFC 5348是一种拥 塞控制协议而不是一种功能齐全的运输层协议。它定义了一种拥塞控制机制该机制能被用于诸如DCCP等其他运输协议事实上在DCCP中可供使用的两种应用程序可选的协议之一就是TFRC。TFRC的目标是平滑在TCP 拥塞控制中的“锯齿”行为同时维护一种长期的发送速率该速率“合理地”接近TCP的速率。使用比TCP更为平滑的发送速率TFRC非常适合诸如IP电话或流媒体等多媒体应用这种平滑的速率对于这些应用是重要的。TFRC是一种“基于方程”的协议这些协议使用测得的丢包率作为方程的输入即使用方程估计一个TCP会话在该丢包率下TCP的吞吐量将是多大。该速率则被取为TFRC的目标发送速率。
http://www.zqtcl.cn/news/130334/

相关文章:

  • 手机网站底部导航网站视频链接怎么做
  • 企业门户网站属于什么层seo关键词排行优化教程
  • wordpress 演示站广东省南粤交通投资建设有限公司网站
  • 典型的企业网站张家港保税区建设规划局网站
  • 网站设计公司那个好网页设计登录界面模板
  • 做网站的厂家聚美优品网站设计
  • 哈尔滨网站建设效果好网站改版 影响google 404跳首页
  • 廊坊网站推广的公司如何做1个手机网站
  • 网站index.php被修改南京cms建站系统
  • 淘宝网站模板是什么做的北海建设厅网站
  • 我想建个网站想做电商应该怎么入门
  • 广州番禺网站制作推广网站建设徐州百度网络网站
  • 有没有个人做网站的新网站做seo 的效果
  • 做网站和app哪个简单旅游资讯网站建设方案
  • 网站建设考级百度怎样可以搜到自己的网站
  • 自助建站免费自助建站网站广州企业网站
  • 常德论坛尚一网唐山seo网络推广
  • 网站建设预付流程网站设计风格的关键词
  • 常德网站制作怎么做自己的网页
  • 做的网站为什么图片看不了wordpress循环该分类子分类
  • 源码出售网站怎么做一个产品的网络营销方案
  • 安丘营销型网站建设国外教育网站模板
  • 做网站案例百度小说排行榜前十
  • 东昌网站建设公司上传到网站去的文档乱码
  • 如何制作自己的网站链接教程网络营销seo招聘
  • 网站制作资料收集wordpress资源网模板
  • 随州网站设计开发服务做网站制作步骤
  • 东莞凤岗做网站黄山旅游攻略住宿
  • 网站开发常用插件免费库存管理软件哪个好
  • 河池网站开发工程师招聘网如何做品牌运营与推广