38

ウェブカメラに接続してソケットから読み取り、印刷機能を使用してこのデータを出力する簡単なリレースクリプトを作成しました。データは、境界が設定されたMJPGデータです。読み取ったデータを出力するだけです。

問題は、PHPがこのデータをバッファリングしているように見えることです。カメラを1FPSに設定すると、フィードが7〜8秒間フリーズし、すぐに8フレームが表示されます。解像度を巨大なサイズに設定すると、カメラはほぼ1秒あたり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);
4

6 に答える 6

67

tl;drバージョン

2つのことを行います。

  1. ユーザースペースの出力バッファを無効にします。

    • 世界的に、どちらかによって...

      • output_bufferingphp.iniでオフにする、または
      • output_bufferingを使用してApache構成でオフにする

        php_flag "output_buffering" Off
        
    • または、気になるスクリプトだけの場合は、...

      • 呼び出しob_end_flush()、または
      • 呼び出しob_end_clean()
  2. また、次のいずれかの方法で、サーバーレベルの出力バッファを可能な限り無効にします。

    • ob_implicit_flush()スクリプトの開始時に呼び出す、または
    • flush()応答本文に出力を追加するすべてechoのステートメントまたは他のステートメントの後に呼び出す

長いバージョン

紛らわしいことに、関連する可能性のあるバッファリングの2つの層があり、PHPドキュメントは2つを区別するのに不十分な仕事をしています。

出力バッファ

最初のレイヤーは通常、PHPドキュメントでは「出力バッファー」と呼ばれます。このバッファリングのレイヤーは、ヘッダーではなく、HTTP応答の本文への出力にのみ影響します。で出力バッファリングをオンにし、またはob_start()でオフにすることができます。php.iniのオプションを使用すると、すべてのスクリプトを出力バッファリングで自動的に開始することもできます。ob_end_flush()ob_end_clean()output_buffering

php.iniの製品版のこのオプションのデフォルト値は4096です。これは、出力の最初の4096バイトが出力バッファーにバッファーされ、その時点でフラッシュされ、出力バッファーがオフになることを意味します。

output_bufferingphp.iniファイルでに設定するOff(またはを使用する)ことにより、このバッファリングのレイヤーをグローバルに無効にすることができます

php_flag "output_buffering" Off

Apacheを使用している場合は、Apache構成で)。または、スクリプトを呼び出すob_end_clean()ob_end_flush()、スクリプトの開始時に、単一のスクリプトに対して無効にすることもできます。

書き込みバッファ、およびWebサーバーバッファ

出力バッファを超えて、PHPマニュアルが「書き込みバッファ」と呼んでいるものに加えて、Webサーバーにあるバッファリングシステムがあります。を介してApacheでPHPを使用していて、をmod_php使用していない場合mod_gzipは、を呼び出しflush()てこれらをフラッシュできます。他のバックエンドでは、それも機能する可能性がありますが、マニュアルは保証を与えることについては慎重です。

説明

void flush ( void )

PHPおよびPHPが使用しているバックエンド(CGI、Webサーバーなど)の書き込みバッファーをフラッシュします。これは、いくつかの注意点を除いて、現在の出力をブラウザにプッシュしようとします。

flush()は、Webサーバーのバッファリングスキームをオーバーライドできない場合があり、ブラウザのクライアント側のバッファリングには影響しません。また、PHPのユーザースペース出力バッファリングメカニズムにも影響しません。つまり、 ob_flush()flush( )の両方を呼び出して、これらを使用している場合は、ob出力バッファーをフラッシュする必要があります。

また、PHPが何かflush()をするたびに自動的に呼び出すようにする(または、出力を応答本文にエコーする他のことを行う)方法もいくつかあります。echo

1つ目はを呼び出すことob_implicit_flush()です。この関数は一見名前が付けられていることに注意してください。接頭辞が与えられるob_と、合理的な人なら誰でも、「出力バッファ」に影響を与えると予想します。たとえば、そうではありません。ただし、そうob_startではありません。のように、サーバーレベルの出力バッファーに影響を与え、他の関数によって制御される出力バッファーとはまったく相互作用しません。ob_flushob_implicit_flush()flush()ob_

2つ目は、php.iniでimplicit_flushフラグをに設定することにより、暗黙的なフラッシュをグローバルに有効にすることです。Onこれはob_implicit_flush()、すべてのスクリプトの開始時に呼び出すのと同じです。マニュアルはこれに反対するようにアドバイスしていることに注意してください。「深刻なパフォーマンスへの影響」を不可解に引用しています。その一部は、この接線方向に関連する回答で調べています。

于 2014-06-08T16:31:15.377 に答える
20

出力バッファリングを無効にするのではなく、flush()すべての読み取り操作の後に呼び出すことができます。これにより、サーバー構成を混乱させる必要がなくなり、スクリプトの移植性が向上します。

于 2012-01-16T15:46:44.620 に答える
14

出力バッファリングは階層化することができ、以前のコードで複数のレベルが作成された場合があります。これにより、すべてがクリアされます。

while (ob_get_level()) ob_end_clean(); 
// or ob_end_flush() if you want the contents of the buffer.
于 2016-10-26T08:38:47.190 に答える
3

PHPで出力バッファリングを無効にするために.htaccessファイルに以下のコードを与えることができます

php_flag "output_buffering" off
于 2013-06-05T12:29:24.140 に答える
0

この質問は少し古いことは知っていますが、この質問に戻ると、次のように、スクリプトごとに出力バッファリングをオフにすることができます。

if (ob_get_level())
   ob_end_clean();

これにより、後続のスクリプトのすべての出力バッファリングがオフになります。

于 2014-04-30T15:41:35.780 に答える
0

Windows IISサーバーの場合、IISは独自のバッファーを管理するため、上記のソリューションはいずれも機能しません。これも無効にする必要があります。

web.configバッファリングを無効にするには、PHPスクリプトを使用してフォルダに以下を追加するだけです。以下の例ではPHPv7.3.7を使用していますが、名前を別のバージョンに置き換えることができます。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <clear />
            <add name="php-7.3.7" path="*.php" verb="GET,HEAD,POST" modules="FastCgiModule" scriptProcessor="C:\Program Files\PHP\v7.3\php-cgi.exe" resourceType="Either" requireAccess="Script" responseBufferLimit="0" />
        </handlers>
    </system.webServer>
</configuration>
于 2019-12-10T23:50:34.420 に答える