在 PHP 中对 popen/fgets 施加时间限制
Impose time limit to popen/fgets in PHP
我想对使用由 PHP 中的 popen 打开的 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 实例之间的连接永远不会关闭,在几次 hours/days 之后有成百上千的 tail 和 httpd 进程 运行 并且服务器启动没有接听。
当然这似乎是一个 AWS Load Balancer 错误,但我不想启动一个过程来获得 Amazon 的关注并等待修复。
我的临时解决方案是执行 sudo kill tail 以在服务器变得不稳定之前终止进程。
我认为 PHP 不会停止脚本,因为 PHP 正在 "blocked" 等待 fgets 完成。
我知道 AWS Load Balancer 的时间限制是可编辑的,但我想保留默认值,即使更高的限制也无法解决问题。
我不知道是否需要将问题更改为如何在具有时间限制/超时的 linux 中执行进程?
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);
我没有使用进程文件指针,而是采用了 "multitasking" 方法。我使用此代码生成其他 "processes" 种多任务作弊。
我调用了一个脚本 hang.php,它只挂起 90 秒:sleep(90)
。
您可能需要调整流和 stream_select 超时。
创建流
header('Content-Type: text/plain; charset=utf-8');
$timeout = 20;
$result = array();
$sockets = array();
$buffer_size = 8192;
$id = 0;
$stream = stream_socket_client("ispeedlink.com:80", $errno,$errstr, $timeout,
STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
if ($stream) {
$sockets[$id++] = $stream; // supports multiple sockets
$http = "GET /testbed/hang.php HTTP/1.0\r\nHost: ispeedlink.com\r\n\r\n";
fwrite($stream, $http);
}
else {
echo "$id Failed\n";
}
可以通过添加流来 运行 其他脚本:$sockets[$id++] = $stream;
下面会将读取的所有内容放入 $result[$id]
数组。
监控流:
while (count($sockets)) {
$read = $sockets;
stream_select($read, $write = NULL, $except = NULL, $timeout);
if (count($read)) {
foreach ($read as $r) {
$id = array_search($r, $sockets);
$data = fread($r, $buffer_size);
if (strlen($data) == 0) { // either reads data or EOF
echo "$id Closed: " . date('h:i:s') . "\n\n\n";
fclose($r);
unset($sockets[$id]);
}
else {
$result[$id] .= $data;
}
}
}
else {
echo 'Timeout: ' . date('h:i:s') . "\n\n\n";
break;
}
}
echo system('ps auxww');
.
当我想终止进程时,我使用 system('ps auxww')
获取 pid 并使用 system("kill $pid")
终止它
kill.php
header('Content-Type: text/plain; charset=utf-8');
//system('kill 220613');
echo system('ps auxww');
我想对使用由 PHP 中的 popen 打开的 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 实例之间的连接永远不会关闭,在几次 hours/days 之后有成百上千的 tail 和 httpd 进程 运行 并且服务器启动没有接听。
当然这似乎是一个 AWS Load Balancer 错误,但我不想启动一个过程来获得 Amazon 的关注并等待修复。
我的临时解决方案是执行 sudo kill tail 以在服务器变得不稳定之前终止进程。
我认为 PHP 不会停止脚本,因为 PHP 正在 "blocked" 等待 fgets 完成。
我知道 AWS Load Balancer 的时间限制是可编辑的,但我想保留默认值,即使更高的限制也无法解决问题。
我不知道是否需要将问题更改为如何在具有时间限制/超时的 linux 中执行进程?
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);
我没有使用进程文件指针,而是采用了 "multitasking" 方法。我使用此代码生成其他 "processes" 种多任务作弊。
我调用了一个脚本 hang.php,它只挂起 90 秒:sleep(90)
。
您可能需要调整流和 stream_select 超时。
创建流
header('Content-Type: text/plain; charset=utf-8');
$timeout = 20;
$result = array();
$sockets = array();
$buffer_size = 8192;
$id = 0;
$stream = stream_socket_client("ispeedlink.com:80", $errno,$errstr, $timeout,
STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
if ($stream) {
$sockets[$id++] = $stream; // supports multiple sockets
$http = "GET /testbed/hang.php HTTP/1.0\r\nHost: ispeedlink.com\r\n\r\n";
fwrite($stream, $http);
}
else {
echo "$id Failed\n";
}
可以通过添加流来 运行 其他脚本:$sockets[$id++] = $stream;
下面会将读取的所有内容放入 $result[$id]
数组。
监控流:
while (count($sockets)) {
$read = $sockets;
stream_select($read, $write = NULL, $except = NULL, $timeout);
if (count($read)) {
foreach ($read as $r) {
$id = array_search($r, $sockets);
$data = fread($r, $buffer_size);
if (strlen($data) == 0) { // either reads data or EOF
echo "$id Closed: " . date('h:i:s') . "\n\n\n";
fclose($r);
unset($sockets[$id]);
}
else {
$result[$id] .= $data;
}
}
}
else {
echo 'Timeout: ' . date('h:i:s') . "\n\n\n";
break;
}
}
echo system('ps auxww');
.
当我想终止进程时,我使用 system('ps auxww')
获取 pid 并使用 system("kill $pid")
kill.php
header('Content-Type: text/plain; charset=utf-8');
//system('kill 220613');
echo system('ps auxww');