2008-09-18 5 views

ответ

16

На прикладном уровне (с использованием API стиля сокетов Berkeley) вы просто смотрите часы и читаете или записываете данные со скоростью, на которую вы хотите ограничить.

Если вы только читаете 10kbps в среднем, но источник отправляет больше, чем это, то в конечном итоге все буферы между ним и вами будут заполняться. TCP/IP позволяет это, и протокол будет способствовать замедлению отправителя (на уровне приложения, вероятно, все, что вам нужно знать, это то, что на другом конце блокировка вызовов записи блокируется, неблокирующие записи будут терпеть неудачу и асинхронны записи не будут завершены, пока вы не прочтете достаточное количество данных, чтобы это разрешить).

На прикладном уровне вы можете быть приблизительным - вы не можете гарантировать жесткие ограничения, такие как «не более 10 килобайт будет пропускать заданную точку в сети за одну секунду». Но если вы будете следить за тем, что вы получили, вы можете получить среднее право в долгосрочной перспективе.

4

Предполагая сетевой транспорт, основанный на TCP/IP, пакеты отправляются в ответ на пакеты ACK/NACK, идущие в другую сторону.

Ограничивая скорость передачи пакетов, подтверждающих получение входящих пакетов, вы в свою очередь уменьшите скорость отправки новых пакетов.

Это может быть немного неточно, поэтому его возможно оптимально контролировать скорость потока вниз и адаптировать скорость ответа адаптивно, пока он не окажется в комфортном пороге. (Это произойдет очень быстро, однако вы отправляете dosens of acks a second)

+0

Не требует ли этого перехода к стеку TCP/IP низкого уровня и обходит стандартный уровень сокета? – Branan 2008-09-18 18:05:14

1

Если вы читаете сокет, вы не контролируете используемую полосу пропускания - вы читаете буфер операционной системы этого сокета, и ничего, что вы говорите, заставит человека, пишущего в сокет, записать меньше данных (если, конечно, вы не разработали для этого протокол).

Все, что медленно читает чтение, это заполнить буфер и вызвать конечный останов в сети, но вы не можете контролировать, как и когда это происходит.

Если вы действительно хотите читать только так много данных, в то время, вы можете сделать что-то вроде этого:

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

Буферы имеют максимальные значения. Cache? Кэш не задействован. – 2008-09-18 18:08:14

0

Wget, кажется, управлять им с опцией --limit курса. Вот со страницы человека:

Обратите внимание, что Wget реализует предельный переспав соответствующее количество времени после того, как сети чтения, которые имели меньше времени, чем указано в скорости. В конце концов эта стратегия приводит к тому, что TCP-передача замедляется до приблизительно указанной ставкой. Однако это может занять некоторое время для . Этот баланс должен быть достигнут, поэтому не надо быть удивленным, если ограничение скорости не работает с очень маленькими файлами.

0

Как уже говорилось, ядро ​​ОС управляет трафиком, и вы просто читаете копию данных из памяти ядра.Чтобы примерно ограничить скорость всего одного приложения, вам необходимо отложить чтение данных и разрешить входящие пакеты в ядре, что в конечном итоге замедлит подтверждение входящих пакетов и снизит скорость на одном сокете.

Если вы хотите замедлить весь трафик на машине, вам нужно пойти и настроить размеры входящих 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() с отправленной длиной меньше ожидаемой длины, передаваемой вызову send().

Если отправитель не готов к работе с этим случаем путем спящего режима и пытается повторно отправить то, что не вписывается в буферы ОС, у вас возникнут проблемы с подключением (отправитель может обнаружить это как ошибку) или потерять данные (отправитель может неосознанно отказаться от данных, которые не вписывались в буферы ОС).

0

Установка буферов для приема и приема небольших сокетов, скажем 1k или 2k, так что продукт задержки * пропускной способности = размер буфера. Возможно, вы не сможете получить его достаточно маленьким по быстрым ссылкам.

Смежные вопросы