代码之家  ›  专栏  ›  技术社区  ›  blackwing

如何限制IO操作?

  •  5
  • blackwing  · 技术社区  · 16 年前

    假设您有一个从套接字读取的程序。如何将下载速率保持在某个给定阈值以下?

    8 回复  |  直到 16 年前
        1
  •  16
  •   Steve Jessop    16 年前

    在应用程序层(使用Berkeley Socket样式的API),您只需观察时钟,并以您希望限制的速度读取或写入数据。

    如果您平均只读取10 Kbps,但源发送的速度超过了10 Kbps,那么最终它与您之间的所有缓冲区都将填满。TCP/IP允许这样做,并且协议将安排发送方放慢速度(在应用层,您可能只需要知道在另一端,阻塞写入调用将阻塞,非阻塞写入将失败,异步写入将无法完成,直到您读取足够的数据来允许它)。

    在应用程序层,您只能是近似值——您不能保证硬限制,例如“任何一秒钟内都不会超过10 kb通过网络中的一个给定点”。但是,如果你跟踪你收到的信息,从长远来看,你可以得到平均值。

        2
  •  4
  •   Kent Fredric    16 年前

    假设网络传输是基于TCP/IP的传输,则发送数据包是为了响应ACK/NACK数据包的另一种方式。

    通过限制确认接收到传入数据包的数据包的速率,您将反过来降低发送新数据包的速率。

    它可能有点不精确,所以它可能是最佳的监测下游速度和适应调整响应速度,直到它落在一个舒适的门槛内。(这种情况很快就会发生,不过,您会发送一秒的ACK剂量)

        3
  •  1
  •   INS    16 年前

    就像把游戏限制在一定数量的fps。

    extern int FPS;
    ....    
    timePerFrameinMS = 1000/FPS;
    
    while(1) {
    time = getMilliseconds();
    DrawScene();
    time = getMilliseconds()-time;
    if (time < timePerFrameinMS) {
       sleep(timePerFrameinMS - time);
    }
    }
    

    这样可以确保游戏刷新率最高为fps。 以同样的方式,drawscene可以是用于将字节泵入套接字流的函数。

        4
  •  1
  •   Branan    16 年前

    如果你从一个套接字读取数据,你就无法控制所用的带宽——你正在读取该套接字的操作系统缓冲区,你所说的任何内容都不会使写入套接字的人写更少的数据(当然,除非你为此制定了一个协议)。

    缓慢读取所要做的就是填满缓冲区,并最终导致网络端的停顿——但您无法控制这种情况的发生方式或时间。

    如果您真的想一次只读取这么多数据,可以这样做:

    ReadFixedRate() {
      while(Data_Exists()) {
        t = GetTime();
        ReadBlock();
        while(t + delay > GetTime()) {
          Delay()'
        }
      }
    }
    
        5
  •  0
  •   Ben Dunlap    16 年前

    wget似乎用限制利率选项来管理它。以下是手册页:

    注意,wget执行限制 通过适当的睡眠 网络读取后花费的时间 比指定的时间短 速率。最终这一策略导致 TCP传输要减速到 约为规定速率。 但是,可能需要一些时间 要达到这个平衡,所以不要 如果限制利率会让人吃惊 小的不好用 文件夹。

        6
  •  0
  •   community wiki jvasak    16 年前

    正如其他人所说,操作系统内核正在管理流量,而您只是从内核内存中读取数据的副本。为了粗略地限制一个应用程序的速率,您需要延迟对数据的读取,并允许传入数据包在内核中进行缓冲,这最终会减慢对传入数据包的确认,并降低该套接字上的速率。

    如果您想降低到机器的所有流量,您需要去调整传入TCP缓冲区的大小。在Linux中,您将通过更改/proc/sys/net/ipv4/tcp_rmem(读取内存缓冲区大小)和其他tcp_ux文件中的值来影响此更改。

        7
  •  0
  •   Jason Plank Maksim Kondratyuk    13 年前

    要补充布兰恩的答案:

    如果您自愿限制接收端的读取速度,那么最终队列将在两端填满。然后,发送方将阻塞其send()调用,或者从send()调用返回,发送长度小于传递给send()调用的预期长度。

    如果发送方没有准备好通过休眠和尝试重新发送不适合OS缓冲区的内容来处理这种情况,您将最终出现连接问题(发送方可能会将此检测为错误)或丢失数据(发送方可能在不知情的情况下丢弃不适合OS缓冲区的数据)。

        8
  •  0
  •   user207421    13 年前

    设置小型套接字发送和接收缓冲区,例如1K或2K,这样带宽*延迟积=缓冲区大小。您可能无法通过快速链接使其足够小。