如何在PHP中禁用输出缓冲

我写了一个简单的中继脚本,连接到一个networking摄像头,并从套接字读取,并使用打印function输出这些数据。 数据是MJPG数据,边界已经设置。 我只输出读取的数据。

问题是PHP似乎在缓冲这个数据。 当我将相机设置为1 FPS时,进纸将会冻结7-8秒,然后快速显示8帧。 如果我将分辨率设置为一个很大的尺寸,相机的移动速度大概是每秒1帧。 我假设一些缓冲正在发生(因为巨大的大小快速填充缓冲区,低大小不),我不知道如何禁用这种缓冲。 有谁知道如何?

码:

ignore_user_abort(false); $boundary = "myboundary"; //Set this so PHP doesn't timeout during a long stream set_time_limit(0); $socketConn = @fsockopen ("192.168.1.6", 1989, $errno, $errstr, 2); if (!$socketConn) exit(); stream_set_timeout($socketConn, 10); fputs ($socketConn, "GET /mjpeg HTTP/1.0\r\n\r\n"); //Setup Header Information header("Cache-Control: no-cache"); header("Cache-Control: private"); header("Pragma: no-cache"); header("Content-type: multipart/x-mixed-replace; boundary=$boundary"); @ini_set('implicit_flush', 1); for ($i = 0; $i < ob_get_level(); $i++) ob_end_flush(); ob_implicit_flush(1); stream_set_blocking($f2, false); //Send data to client while (connection_status() == CONNECTION_NORMAL) { $chunk = fread($socketConn, 128); print $chunk; } fclose($socketConn); 

tl; dr版本

做两件事:

  1. 禁用用户空间输出缓冲区,或者…

    • 在全球范围内,通过…

      • closuresphp.ini中的output_buffering ,或者
      • 在你的Apacheconfiguration中使用closuresoutput_buffering

         php_flag "output_buffering" Off 
    • 或只是你关心的脚本,通过…

      • 调用ob_end_flush()或者
      • 调用ob_end_clean()
  2. 此外,通过以下任一方法尽可能地禁用服务器级输出缓冲区:

    • 在脚本开始时调用ob_implicit_flush() ,或者
    • 在每个echo语句或其他将输出添加到响应主体的语句之后调用flush()

更长的版本

令人困惑的是,有两层缓冲可能是相关的,而PHP文档在区分这两者方面做得不好。

输出缓冲区

第一层通常被PHP文档称为“输出缓冲区”。 这个缓冲层只影响输出到HTTP响应的主体 ,而不是头部。 您可以使用ob_start()打开输出缓冲,并使用ob_end_flush()ob_end_clean()将其closures。 您也可以使用php.ini中的output_buffering选项,让所有脚本自动启动输出缓冲。

对于生产版本的php.ini ,这个选项的默认值是4096,这意味着输出的前4096个字节将被缓冲在输出缓冲区中,在这一点上它将被刷新并且输出缓冲被closures。

你可以通过在你的php.ini文件中设置output_buffering Off来全局禁用这个缓冲层

 php_flag "output_buffering" Off 

在你的Apacheconfiguration中,如果你使用的是Apache)。 或者,您可以通过在脚本开始时调用ob_end_clean()ob_end_flush()来禁用单个脚本。

写入缓冲区和Web服务器缓冲区

除了输出缓冲区之外,PHP手册指的是“写缓冲区”,再加上您的Web服务器所具有的任何缓冲系统。 如果你通过mod_php和Apache一起使用PHP,并且不使用mod_gzip ,你可以调用flush()来刷新这些; 与其他后端,它也可能工作,虽然手册是谨慎的保证:

描述

 void flush ( void ) 

刷新PHP的写缓冲区和任何后端PHP正在使用(CGI,一个Web服务器等)。 这会试图将电stream输出一路推送到浏览器,但有一些注意事项。

flush()可能无法覆盖您的Web服务器的缓冲scheme,并且对浏览器中的任何客户端缓冲都没有影响。 它也不影响PHP的用户空间输出缓冲机制。 这意味着如果使用ob_flush()和flush()来刷新ob输出缓冲区,则必须调用它们。

还有几种方法可以让PHP在每次echo任何东西时自动调用flush() (或者做任何其他回声输出到响应主体的东西)。

首先是调用ob_implicit_flush() 。 请注意,此function是欺骗性地命名; 给定它的ob_前缀,任何合理的人都会期望它会影响“输出缓冲区”, ob_startob_flush等也是ob_flush 。但事实并非如此。 ob_implicit_flush() (如flush()会影响服务器级输出缓冲区,并且不会与其他ob_函数控制的输出缓冲区进行任何交互。

第二个是通过在php.ini中设置implicit_flush标志为On来全局启用隐式刷新。 这相当于在每个脚本开始时调用ob_implicit_flush() 。 请注意,手册build议反对这一点,密码引用“严重的性能影响” ,其中一些我在这个切线相关的答案探讨。

而不是禁用输出缓冲,您可以在每次读取操作后调用flush() 。 这样可以避免混淆服务器configuration,使脚本更加便于携带。

我们可以在.htaccess文件中给出下面的代码来禁用PHP中的输出缓冲

 php_flag "output_buffering" off 

输出缓冲可以分层,我已经有了更早的代码已经多层次的情况。 这将清除所有。

 while (ob_get_level()) ob_end_clean(); // or ob_end_flush() if you want the contents of the buffer. 

我知道这个问题有点老了,但回到这个问题,你可以closures脚本输出缓冲到脚本的基础上,像这样:

 if (ob_get_level()) ob_end_clean(); 

这应该closures所有后续脚本的输出缓冲。