2008-09-18 74 views

回答

16

在应用程序层(使用Berkeley套接字样式API),您只需观察时钟,然后以您想限制的速率读取或写入数据。

如果你只在平均读取10kbps的,但源发送不止这些,那么最终所有的IT之间的缓冲区,你将填补。 TCP/IP允许这样做,并且协议将安排发送者放慢速度(在应用层,可能你所需要知道的是,在另一端阻塞写入调用将被阻塞,非阻塞写入将失败,并且异步写入不会完成,直到你已经读取足够的数据来允许它)。

在应用程序层,您只能近似 - 您不能保证硬限制,例如“不超过10 kb将在任何一秒内通过网络中的给定点”。但是如果你跟踪你收到的东西,你可以从长远来看获得平均的权利。

4

假设一个网络传输,基于IP的一个TCP /,分组被在响应发送到ACK/NACK数据包正在的其他方式。

通过限制确认收到传入数据包的数据包的速度,你会反过来抑制用于新的数据包的发送速率。

它可以是一个位不精确,因此,其可能最佳监视下行速率和调整响应速率自适应,直到它落在舒适阈值内。 (然而,这真的很快发生,你发送一秒的ACK)

+0

这不需要转到低级TCP/IP堆栈,并绕过标准套接字层? – Branan 2008-09-18 18:05:14

1

如果你从一个套接字读取,你无法控制使用的带宽 - 你正在读取该套接字的操作系统的缓冲区,并且你所说的任何话都不会让写入套接字的人写入更少的数据(除非你已经为此编写了一个协议)。

缓慢读取的所有内容都会填满缓冲区,并导致网络端发生最终失速 - 但您无法控制发生这种情况的方式或时间。

如果你真的想在一次只读如此多的数据,你可以做这样的事情:

ReadFixedRate() { 
    while(Data_Exists()) { 
    t = GetTime(); 
    ReadBlock(); 
    while(t + delay > GetTime()) { 
     Delay()' 
    } 
    } 
} 
+0

缓冲区具有最大值。缓存?没有涉及缓存。 – 2008-09-18 18:08:14

0

的wget似乎与--limit-rate选项来管理它。下面是从该名男子页:

注意Wget在网络阅读时间比由 率指定 更短的时间后睡觉的时间 适量实现限制 。最终,此策略导致 TCP传输大约以指定速率减慢至 。 但是, 可能需要一段时间才能达到此余额,因此如果限制费率 对于非常小的 文件不起作用,则不会令 感到意外。

0

正如其他人所说,OS内核是管理交通,你只是在读取数据的副本出的内核内存。要大致限制一个应用程序的速率,您需要延迟读取数据并允许传入数据包在内核中缓冲,这最终会减慢对传入数据包的确认速度,并降低该数据包的速率。

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

1

这就像将游戏限制在一定数量的FPS时一样。

extern int FPS; 
....  
timePerFrameinMS = 1000/FPS; 

while(1) { 
time = getMilliseconds(); 
DrawScene(); 
time = getMilliseconds()-time; 
if (time < timePerFrameinMS) { 
    sleep(timePerFrameinMS - time); 
} 
} 

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

0

为了增加Branan的回答是:

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

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

0

设置小插座发送和接收缓冲区,比如说1k或2k,这样带宽*延迟乘积=缓冲区大小。您可能无法通过快速链接获得足够小的空间。