• 计算机网络【7】—— TCP的精髓


    参考文献:

    http://blog.chinaunix.net/uid-26275986-id-4109679.html

    TCP协议作为一个可靠的面向流的传输协议,其可靠性和流量控制由滑动窗口协议保证,而拥塞控制则由控制窗口结合一系列的控制算法实现。

    一、滑动窗口协议

         关于这部分自己不晓得怎么叙述才好,因为理解的部分更多,下面就用自己的理解来介绍下TCP的精髓:滑动窗口协议

         所谓滑动窗口协议,自己理解有两点:1. “窗口”对应的是一段可以被发送者发送的字节序列,其连续的范围称之为“窗口”;2. “滑动”则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序“滑动”。在引入一个例子来说这个协议之前,我觉得很有必要先了解以下前提:

    1. TCP协议的两端分别为发送者A和接收者B,由于是全双工协议,因此A和B应该分别维护着一个独立的发送缓冲区和接收缓冲区,由于对等性(A发B收和B发A收),我们以A发送B接收的情况作为例子;
    2. 发送窗口是发送缓存中的一部分,是可以被TCP协议发送的那部分,其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区;
    3. 发送窗口中相关的有四个概念:
      • 已发送并收到确认的数据(不再发送窗口和发送缓冲区之内)
      • 已发送但未收到确认的数据(位于发送窗口之中)
      • 允许发送但尚未发送的数据
      • 发送窗口外发送缓冲区内暂时不允许发送的数据;

      4. 每次成功发送数据之后,发送窗口就会在发送缓冲区中按顺序移动,将新的数据包含到窗口中准备发送;

         TCP建立连接的初始,B会告诉A自己的接收窗口大小,比如为‘20’:

         字节31-50为发送窗口


         A发送11个字节后,发送窗口位置不变,B接收到了乱序的数据分组:

         只有当A成功发送了数据,即发送的数据得到了B的确认之后,才会移动滑动窗口离开已发送的数据;同时B则确认连续的数据分组,对于乱序的分组则先接收下来,避免网络重复传递:


    二、流量控制

         流量控制方面主要有两个要点需要掌握。一是TCP利用滑动窗口实现流量控制的机制;二是如何考虑流量控制中的传输效率

    1. 流量控制

         所谓流量控制,主要是接收方传递信息给发送方,使其不要发送数据太快,是一种端到端的控制。主要的方式就是返回的ACK中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送:

         这里面涉及到一种情况,如果B已经告诉A自己的缓冲区已满,于是A停止发送数据;等待一段时间后,B的缓冲区出现了富余,于是给A发送报文告诉A我的rwnd大小为400,但是这个报文不幸丢失了,于是就出现A等待B的通知||B等待A发送数据的死锁状态。为了处理这种问题,TCP引入了持续计时器(Persistence timer),当A收到对方的零窗口通知时,就启用该计时器,时间到则发送一个1字节的探测报文,对方会在此时回应自身的接收窗口大小,如果结果仍未0,则重设持续计时器,继续等待。

    2. 传递效率

         一个显而易见的问题是:单个发送字节单个确认,和窗口有一个空余即通知发送方发送一个字节,无疑增加了网络中的许多不必要的报文(请想想为了一个字节数据而添加的40字节头部吧!),所以我们的原则是尽可能一次多发送几个字节,或者窗口空余较多的时候通知发送方一次发送多个字节。对于前者我们广泛使用Nagle算法,即:
    *1. 若发送应用进程要把发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面的字节先缓存起来;
    *2. 当发送方收到第一个字节的确认后(也得到了网络情况和对方的接收窗口大小),再把缓冲区的剩余字节组成合适大小的报文发送出去;
    *3. 当到达的数据已达到发送窗口大小的一半或以达到报文段的最大长度时,就立即发送一个报文段;
         对于后者我们往往的做法是让接收方等待一段时间,或者接收方获得足够的空间容纳一个报文段或者等到接受缓存有一半空闲的时候,再通知发送方发送数据。

    三、拥塞控制

         网络中的链路容量和交换结点中的缓存和处理机都有着工作的极限,当网络的需求超过它们的工作极限时,就出现了拥塞。拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。常用的方法就是:
      、拥塞控制快重传、快恢复 ) 
         一切的基础还是慢开始,这种方法的思路是这样的:
    -1. 发送方维持一个叫做“拥塞窗口”的变量,该变量和接收端口共同决定了发送者的发送窗口;
    -2. 当主机开始发送数据时,避免一下子将大量字节注入到网络,造成或者增加拥塞,选择发送一个1字节的试探报文;
    -3. 当收到第一个字节的数据的确认后,就发送2个字节的报文;
    -4. 若再次收到2个字节的确认,则发送4个字节,依次递增2的指数级;
    -5. 最后会达到一个提前预设的“慢开始门限”,比如24,即一次发送了24个分组,此时遵循下面的条件判定:
      *1. cwnd < ssthresh, 继续使用慢开始算法;
      *2. cwnd > ssthresh,停止使用慢开始算法,改用拥塞避免算法;
      *3. cwnd = ssthresh,既可以使用慢开始算法,也可以使用拥塞避免算法;
    -6. 所谓拥塞避免算法就是:每经过一个往返时间RTT就把发送方的拥塞窗口+1,即让拥塞窗口缓慢地增大,按照线性规律增长;
    -7. 当出现网络拥塞,比如丢包时,将慢开始门限设为原先的一半,然后将cwnd设为1,执行慢开始算法(较低的起点,指数级增长);

         上述方法的目的是在拥塞发生时循序减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够的时间把队列中积压的分组处理完毕。慢开始和拥塞控制算法常常作为一个整体使用,而快重传和快恢复则是为了减少因为拥塞导致的数据包丢失带来的重传时间,从而避免传递无用的数据到网络。快重传的机制是:
    -1. 接收方建立这样的机制,如果一个包丢失,则对后续的包继续发送针对该包的重传请求;
    -2. 一旦发送方接收到三个一样的确认,就知道该包之后出现了错误,立刻重传该包;
    -3. 此时发送方开始执行“快恢复”算法:
    *1. 慢开始门限减半;
    *2. cwnd设为慢开始门限减半后的数值;
    *3. 执行拥塞避免算法(高起点,线性增长);
     

    四、可靠传输的停止等待协议和连续ARQ协议

    网络传输的理想传输状态就是:

        1、传输信道不产生差错。

        2、不管发送方以多块的速度发送数据,接收方都能来得及接受以及处理这些数据。

    当然,这种只是理想状态,在实际运用中,几乎是不可能的。因此,我们需要采取一些可靠的传输协议。

        1、当出现差错时,让发送发重传该差错数据。

        2、接受方来不及处理数据时,及时告知发送方适当的降低发送速度。

    那么,要做到上述第一点,就需要采用:停止等待协议   

    1. 停止等待协议

        所谓停止等待协议就是没发送完一组数据后,等待对方确认并且收到确认后,再发送下一组数据。

        我将它简单的理解为以下过程:发送数据,收到数据,发送确认,收到确认。

        那么这样,就分为了以下4种情况。(无差错、出现差错、确认丢失、确认迟到)

        1、无差错

            

           

            所谓无差错,就是数据能够正常发送,正常接收,正常确认,正常收到确认的一个过程。也是最理想,最好的一种状态。

        2、出现差错

            

            所谓出现差错,就是数据在发送的过程中部分或全部丢失(如上图左)。

            A发送M1并出现差错,B在收到M1时(全部丢失,不会收到)检测出了差错,就丢弃M1,其他什么也不做(不会通知A数据出现了差错,因为有可能全部丢失,B并不知道)。在这两种情况下,B都不会发送任何的信息。那么,怎么办?

            A只要超过一段时间仍然没有收到确认,就认为刚才所发送的数据丢失,然后重传前面发送的数据。这就叫做超时重传。当前需要一个计时器来完成。

            因此,有如下三点要求:

            1>、A在发送完一组数据后,必须暂时保留自己已发送的数据的副本(供超时重传使用)。只有收到确认后,才会删除该副本。

            2>、每一组数据和确认数据都必须编号(TCP头部有该字段)。这样才能明确是哪一个发送出去的数据收到了确认,哪一个没有收到。

            3>、超时计时器设定的时间应该要长于数据平均往返时间。

        3、确认丢失

            

            所谓确认丢失,其实就是确认消息在传输过程丢失。那么,该如何处理?

            当A发送M1消息,B收到后,B向A发送了一个M1确认消息,但却在传输过程中丢失。而A并不知道,在超时计时过后,A重传M1消息,B再次收到该消息后采取以下两点措施:

            1>、丢弃这个重复的M1消息,不向上层交付。

            2>、向A发送确认消息。(不会认为已经发送过了,就不再发送。A能重传,就证明B的确认消息丢失)。

        4、确认迟到

            

            所谓确认迟到,就是B发送的确认消息没有丢失,但是却迟到(过了很长一段时间才到)。那么该如何处理?

            A发送M1消息,B收到并发送确认。在超时时间内没有收到确认消息,A重传M1消息,B仍然收到并继续发送确认消息(B收到了2份M1)。此时A收到了B第二次发送的确认消息。接着发送其他数据。过了一会,A收到了B第一次发送的对M1的确认消息(A也收到了2份确认消息)。处理如下:

            1>、A收到重复的确认后,直接丢弃。

            2>、B收到重复的M1后,也直接丢弃重复的M1。

        至此,就是停止等待协议中所出现的所有的可能情况。也一一解决。像这种可靠的传输协议通常称为自动重传请求ARQ(Automatic Repeat reQuest)。意思就是,重传的请求是自动进行的,不需要接受方请求发送某一个丢失或出错的消息。

        但是,很显然。我们发现,其信道的利用率很低。

        那该怎么办?

        那就是利用连续ARQ请求协议。

    2. 连续ARQ协议  

      先看一张信道利用率图:

        这两张图的差异很明显。使用连续的ARQ协议可以大大的提高信道利用率。

        吧后者这张图的工作模式又叫做流水线传输。

        其原理如下:

        

         其实现的基础是建立在滑动窗口之上。而滑动窗口乃是TCP的精髓所在(下一篇详解)。

         连续ARQ规定,发送方每收到一个确认就将滑动窗口向前(时间增大方向)滑动一格。如上图表示收到一个确认。

         接受方采用累积确认的方式:接收方不必每收到一个消息,就发送一个确认。而是在收到几条消息后,对按序到达的最后一条消息发送确认。表示,这个消息之前的所有消息全部收到。

       

        当然,这两个方式都有自己的优缺点:

        1、自动重传请求ARQ协议

         优点:简单

         缺点:信道利用率低

        2、连续的ARQ协议

        优点:信道利用率高,容易实现,即使确认丢失,也不必重传。

        缺点:不能向发送方反映出接收方已经正确收到的所有分组的信息。

        比如:发送方发送了5条消息,中间第三条丢失(3号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫

    Go-Back-N(回退N),表示需要退回来重传已经发送过的N个消息。

     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    1-1 10:超级玛丽游戏
    1-1 09:字符菱形
    【Lucene4.8教程之四】分析
    【Lucene4.8教程之六】QueryParser与Query子类:如何生成Query对象
    【Lucene4.8教程之三】搜索
    Java路径问题最终解决方案—可定位所有资源的相对路径寻址
    java.util.logging.Logger基础教程
    【Lucene4.8教程之二】索引
    【Lucene4.8教程之一】使用Lucene4.8进行索引及搜索的基本操作
    重要学习参考资料
  • 原文地址:https://www.cnblogs.com/bopo/p/9253402.html
Copyright © 2020-2023  润新知