默认stream_get_contents
等待并聆听60秒。
如果我有多个流,并想继续听所有流。
如果我正在收听一个流,我会听不到其他流。
连续监听和捕获所有流的流输出的解决方案是什么?
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 multiplexing
,在30分钟内,每个单独的流只会录制6分钟
我有一个解决方案可以为各个流提供AJAX请求并独立记录。 当然我不想做这个多AJAX调用方法,因为它会导致更多的代码以及更多的CPU。
答案 0 :(得分:6)
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) {
// 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
$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);
答案 1 :(得分:1)
PHP在服务器上作为单个进程运行。执行此类操作的“最佳”方法是为每个流生成一个线程。每个线程都有一个要监听的流。多线程自动利用多个CPU并允许它们并行运行。
不幸的是,PHP确实不允许您创建线程。但是,有两种解决方法可供选择(注意:this question可能会对您有所帮助)。
选项1:克隆流程
PHP 允许您使用pcntl_fork等函数克隆当前进程。基本上,您可以创建当前PHP进程的副本,该进程将接管并开始运行。只需为需要收听的每个流执行此操作。复杂性将确保每个进程都监听正确的流。 (提示:有一个流列表,并使用一个标志到列表中的下一个流。然后执行fork [克隆进程]。子进程将开始侦听该流。但是,在父级中,将标志更新为列表中的下一个流,并创建另一个子级,例如......)
选项2:多个PHP实例
您可以使用Cronjob,多个调用或其他服务(甚至是命令行调用)来调用每个PHP脚本,或者将参数传递给脚本以标识要侦听的流。这将并行运行每个PHP脚本/文件,并实现您的目标。
选项3:不要使用PHP
PHP在技术上并不是为这样的东西构建的,这可能很容易用C,C ++或Java实现。你应该重新考虑你的设置。
选项4:创建PHP或Apache模块
您可以在C中为PHP或Apache编写一个模块,然后在PHP中使用您的函数调用。这可能会非常复杂,我不推荐它。
总而言之,我建议您重新考虑您的设置而不是使用PHP。但是如果你只局限于PHP,那么可以采用多种AJAX调用方式。
答案 2 :(得分:1)
连续监听和捕获所有流的流输出的解决方案是什么?
This issue一直困扰程序员很长一段时间。如果你正在为你的问题找到一个合适的解决方案,那么W. Richard Stevens写的一本名为UNIX Network Programming的书将是一个非常好的起点。