我想对使用 popen 在 PHP 中打开的 fgets 的进程读取施加时间限制。
我有下一个代码:
$handle = popen("tail -F -n 30 /tmp/pushlog.txt 2>&1", "r");
while(!feof($handle)) {
$buffer = fgets($handle);
echo "data: ".$buffer."\n";
@ob_flush();
flush();
}
pclose($handle);
我试过没有成功:
set_time_limit(60);
ignore_user_abort(false);
过程如下:
- 浏览器发送 GET 请求等待 HTML5 服务器端的应答 事件格式。
- 请求由 AWS Load Balancer 接收并且是 转发到 EC2 实例。
- 答案是文件的最后 30 行
- 浏览器在 30 条消息中收到它并保持连接。
- 如果 tail 命令发送一个新行,它会被返回,否则 fgets 会等待未定义的时间,直到从 tail 命令返回新行。
- AWS Load Balancer 在网络不活动 60 秒后(60 秒内无新行)关闭与浏览器的连接。与 EC2 实例的连接未关闭。
- 浏览器检测到连接已关闭,并打开一个新连接,返回步骤1。
如该步骤所述,AWS Load Balancer 和 EC2 实例之间的连接永远不会关闭,几个小时/几天后,有成百上千个 tail 和 httpd 进程在运行,服务器开始不响应。
当然这似乎是 AWS Load Balancer 错误,但我不想启动一个流程来获得 Amazon 的关注并等待修复。
我的临时解决方案是执行 sudo kill tail 以在服务器变得不稳定之前终止进程。
我认为 PHP 不会停止脚本,因为 PHP 正在“阻塞”等待 fgets 完成。
我知道 AWS Load Balancer 的时间限制是可编辑的,但我想保留默认值,即使更高的限制也无法解决问题。
我不知道是否需要将问题更改为 How to execute a process in linux with a time limit/timeout?。
PHP 5.5.22/Apache 2.4/Linux 内核 3.14.35-28.38.amzn1.x86_64
最佳答案
使用 PHP 5.5.20 测试:
//Change configuration.
set_time_limit(0);
ignore_user_abort(true);
//Open pipe & set non-blocking mode.
$descriptors = array(0 => array('file', '/dev/null', 'r'),
1 => array('pipe', 'w'),
2 => array('file', '/dev/null', 'w'));
$process = proc_open('exec tail -F -n 30 /tmp/pushlog.txt 2>&1',
$descriptors, $pipes, NULL, NULL) or exit;
$stream = $pipes[1];
stream_set_blocking($stream, 0);
//Call stream_select with a 10 second timeout.
$read = array($stream); $write = NULL; $except = NULL;
while (!feof($stream) && !connection_aborted()
&& stream_select($read, $write, $except, 10)) {
//Print out all the lines we can.
while (($buffer = fgets($stream)) !== FALSE) {
echo 'data: ' . $buffer . "\n";
@ob_flush();
flush();
}
}
//Clean up.
fclose($stream);
$status = proc_get_status($process);
if ($status !== FALSE && $status['running'] === TRUE)
proc_terminate($process);
proc_close($process);
关于php - 在 PHP 中对 popen/fgets 施加时间限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30227531/