Как ограничить скорость исходящего ответа из php скрипта?

Как ограничить скорость исходящего ответа из php скрипта? Поэтому у меня есть скрипт, генерирующий данные в keep-alive соединении. Он просто открывает файл и читает его. Как ограничить исходящую скорость

(Сейчас у меня есть такой код)

if(isset($_GET[FILE]))
 {
  $fileName = $_GET[FILE];
  $file =  $fileName;

  if (!file_exists($file))
  {
   print('<b>ERROR:</b> php could not find (' . $fileName . ') please check your settings.'); 
   exit();
  }
  if(file_exists($file))
  {
   # stay clean
   @ob_end_clean();
   @set_time_limit(0);

   # keep binary data safe
   set_magic_quotes_runtime(0);

   $fh = fopen($file, 'rb') or die ('<b>ERROR:</b> php could not open (' . $fileName . ')');
   # content headers
   header("Content-Type: video/x-flv"); 

   # output file
   while(!feof($fh)) 
   {
     # output file without bandwidth limiting
     print(fread($fh, filesize($file))); 
   } 
  } 
 }

Итак, что мне делать, чтобы ограничить скорость отклика (например, до 50 кбит / с)

5 ответов

Решение

Измените вывод файла так, чтобы он располагался в шахматном порядке, а не выводил весь файл за один раз.

# output file
while(!feof($fh)) 
{
    # output file without bandwidth limiting
    print(fread($fh, 51200)); # 51200 bytes = 50 kB
    sleep(1);
}

Это выдаст 50 кБ, затем подождите одну секунду, пока не будет выведен весь файл. Он должен ограничить полосу пропускания примерно до 50 кБ / с.

Хотя это возможно в PHP, я бы использовал ваш веб-сервер для управления дросселированием.

Я бы не стал использовать php для ограничения пропускной способности:

Для Apache: Bandwidth Mod v0.7 ( How-To - Ограничение пропускной способности для Apache2)

Для Nginx: http://wiki.nginx.org/NginxHttpCoreModule

Для Lighttpd: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:TrafficShaping Это даже позволяет вам настроить скорость на соединение в PHP

Вы можете прочитать n байтов, а затем использовать команду sleep(1), чтобы подождать секунду, как предлагается здесь.

Вы можете прикрепить bandwidth-throttle/bandwidth-throttle в поток:

use bandwidthThrottle\BandwidthThrottle;

$in  = fopen(__DIR__ . "/resources/video.mpg", "r");
$out = fopen("php://output", "w");

$throttle = new BandwidthThrottle();
$throttle->setRate(500, BandwidthThrottle::KIBIBYTES); // Set limit to 500KiB/s
$throttle->throttle($out);

stream_copy_to_stream($in, $out);

Я думаю, что метод 'Ben S' и 'igorw' неправильный, потому что они подразумевают неограниченную пропускную способность, что является ложным предположением. В основном сценарий, который говорит

while(!feof($fh)) {
   print(fread($fh, $chunk_size));
   sleep(1);
}

остановится на секунду после вывода количества байтов в $chunk_size независимо от того, сколько времени это заняло. Если, например, если ваша текущая пропускная способность составляет 100 КБ, а вы хотите осуществлять потоковую передачу на 250 КБ, приведенный выше сценарий займет 2,5 секунды для выполнения print(), а затем подождет еще одну секунду, эффективно уменьшив реальную пропускную способность примерно до 70 КБ.

Решение должно либо измерить время, необходимое PHP для завершения statemnt print(), либо использовать буфер и вызывать flush для каждого fread(). Первый подход будет следующим:

list($usec, $sec) = explode(' ', microtime());
$time_start = ((float)$usec + (float)$sec);
# output packet
print(fread($fh, $packet_size));
# get end time
list($usec, $sec) = explode(' ', microtime());
$time_stop = ((float)$usec + (float)$sec);
# wait if output is slower than $packet_interval
$time_difference = $time_stop - $time_start;
if($time_difference < (float)$packet_interval) {
    usleep((float)$packet_interval*1000000-(float)$time_difference*1000000);
}

в то время как второй будет что-то вроде:

ob_start();
while(!feof($fh)) {
       print(fread($fh, $chunk_size));
       flush();
       ob_flush();
       sleep(1);
    }
Другие вопросы по тегам