3

デフォルトstream_get_contentsでは、60秒間待機してリッスンします。複数のストリームがあり、それらすべてを継続的に聴きたい場合。

foreach内で、1つのストリームを聞いていると、他のストリームを聞くことができません。

すべてのストリームのストリーム出力を継続的にリッスンしてキャプチャするためのソリューションは何ですか?

while(true){
   //$streamArray is an array of streams obtained by stream_socket_client("tcp://..);
   foreach($streamArray as $stream){
        fputs($stream,$command);
        stream_get_contents($stream);  // and update file/DB (Blocking call)
        }
    }

注:すべてのストリームについて、私はすでに実行しましたstream_set_blocking( $stream , true );

アップデート:

私の要件は、すべてのストリームをしばらくの間、たとえば30分聞くことです。同時に私は2つのストリームを聞くことができません。ストリームが5つある場合、コードはtime division multiplexing30分のうち、個々のストリームは6分だけ記録されます。

個々のストリームとレコードに対して個別にAJA​​Xリクエストを行うソリューションが1つあります。確かに、この複数のAJAX呼び出しメソッドを実行したくないのは、コードとCPUが増えるためです。

4

3 に答える 3

7

stream_set_blocking($resource, true)ストリームの読み取りを同期的に開始します。つまり、各呼び出しfread()は、読み取るデータができるまで待機します。次に、を呼び出しますstream_get_contents()。これは、EOFに到達する(閉じられる)までブロッキングストリームから読み取ります。その結果、「同時に」ではなく、次々にストリームを読み取ることになります。

この方法でストリームを読み取ることは一般的であり、コーディングが最も簡単ですが、複数のストリームを同時に処理する場合は、バッファー、タイミング、および「ストリームの終わり」の検出を自分で処理する必要があります。現在のコードでは、この部分はブロックストリームとを介して抽象化されていますstream_get_contents()

複数のストリームを同時に読み取るには、ストリームを非同期に読み取るようにコードを書き直す必要があります。

// $streamArray is an array of streams obtained by stream_socket_client("..");

$buffers = array();
$num_streams = 0;
foreach($streamArray as $stream) {
    // set streams non-blocking for asynchroneous reading
    stream_set_blocking($stream, false);
    // write command to all streams - multiplexing
    fputs($stream, $command);
    // initialize buffers
    $buffers[$stream] = '';
    $num_streams++;
}
while($num_streams > 0) {
    // use stream_select() to wait for new data and not use CPU at 100%.
    // note that the stream arrays are passed by reference and are modified
    // by stream_select() to reflect which streams are modified / have a
    // new event. Because of this we use a copy of the original stream array.
    // also note that due to a limitation in ZE you can not pass NULL directly
    // for more info: read the manual    https://php.net/stream_select
    $no_stream = NULL;
    $select_read = $streamArray;
    stream_select($select_read, $no_stream, $no_stream, null);

    // if there is new data, read into the buffer(s)
    foreach($select_read as $stream) {
        $buffers[$stream] .= fread($stream, 4096);
        // check if the stream reached end
        if (feof($stream)) {
            $key = array_search($stream, $streamArray);
            // close stream properly
            $num_streams--;
            fclose($stream);
            // remove stream from array of open streams
            unset($streamArray[$key]);
        }
    }
}
// do something with your buffers - our use them inside the while() loop already
print_r($buffers);
于 2012-07-28T23:50:35.613 に答える
1

PHPは、サーバー上で単一のプロセスとして実行されます。このようなことを行うための「最良の」方法は、ストリームごとにスレッドを生成することです。各スレッドには、リッスンする単一のストリームがあります。マルチスレッドは自動的に複数のCPUを利用し、それらを並行して実行できるようにします。

残念ながら、PHPではスレッドを作成できません。ただし、回避策にはいくつかのオプションがあります(注:この質問は、いくつかの利点がある場合があります)。

オプション1:プロセスのクローンを作成する

PHPでは、 pcntl_forkなどの関数を使用して現在のプロセスのクローンを作成できます。基本的に、現在のPHPプロセスのコピーを作成すると、そのプロセスが引き継いで実行を開始します。聞く必要のあるストリームごとにそれを行うだけです。複雑なのは、各プロセスが正しいストリームをリッスンすることを確認することです。(ヒント:ストリームのリストを用意し、リスト内の次のストリームへのフラグを使用します。次に、フォーク[プロセスの複製]を実行します。子プロセスはそのストリームのリッスンを開始します。ただし、親では、フラグを更新します。リスト内の次のストリームに移動し、別の子を作成するなど...)

オプション2:複数のPHPインスタンス

Cronjob、複数の呼び出し、またはその他のサービス(コマンドライン呼び出しも含む)を使用して、各PHPスクリプトを呼び出すか、スクリプトにパラメーターを渡して、リッスンするストリームを識別することができます。これにより、各PHPスクリプト/ファイルが並行して実行され、必要なものが実現されます。

オプション3:PHPを使用しない

PHPは、このようなもののために技術的に構築されたものではなく、おそらくC、C ++、またはJavaで簡単に実現できます。セットアップを再考する必要があります。

オプション4:PHPまたはApacheモジュールを作成する

PHPまたはApache用のCでモジュールを作成し、PHP内から関数呼び出しを使用できます。これはおそらくかなり複雑になるので、お勧めしません。

全体として、PHPを使用せずに、セットアップを再考することをお勧めします。ただし、PHPに限定されている場合は、複数のAJAX呼び出しが最適です。

于 2012-07-28T23:40:37.090 に答える
1

すべてのストリームのストリーム出力を継続的にリッスンしてキャプチャするためのソリューションは何ですか?

この問題は、かなり長い間プログラマーを悩ませてきました。W.リチャードスティーブンスによって書かれたUNIXネットワークプログラミングと呼ばれる本は、あなたがあなたの問題のまともな解決策を求めているなら、非常に良い出発点になるでしょう。

于 2012-07-28T23:44:06.303 に答える