PHP非阻塞执行系统命令
在Web开发中,有时候需要在PHP脚本中执行一些后台操作或系统命令。常见的方法是使用PHP提供的exec()
或shell_exec()
等函数。但是这些函数都是阻塞式的,也就是说当命令执行时,PHP脚本会一直等待,直到命令执行完成后才继续执行下面的代码。如果要执行的命令比较耗时,就会导致整个应用的性能下降。
为了解决这个问题,可以使用PHP的非阻塞执行命令的技术。在这篇文章中,我们将介绍如何使用PHP的扩展库pcntl和stream_socket_client实现非阻塞执行系统命令。
安装PCNTL扩展
PCNTL(Process Control)扩展是PHP的一个内置扩展,在不同的发行版下可能需要单独安装。在安装之前,需要确认PHP版本和架构,安装好PCNTL后,在php.ini文件中新增扩展配置:
extension=pcntl.so
执行非阻塞命令
下面是使用pcntl和stream_socket_client执行非阻塞命令的步骤:
- 创建一个socket客户端连接:
$socket = stream_socket_client('tcp://127.0.0.1:80', $errno, $errstr);
// 用于socket的标准输入输出
$stdin = $stdout = $stderr = $socket;
- 启动一个子进程,执行系统命令:
$pid = pcntl_fork();
if ($pid == -1) {
// fork失败
exit('Error: fork failed');
} elseif ($pid == 0) {
// 启动一个子进程,执行要执行的命令
exec('ls -l', $output, $return_var);
exit;
}
- 在父进程中,监听子进程的输出并进行相关处理:
// 开启非阻塞输入输出,并创建read的数组
stream_set_blocking($stdout, false);
stream_set_blocking($stderr, false);
$read = [$stdout, $stderr];
// 循环读取子进程的标准输入输出
while (!feof($stdout) || !feof($stderr)) {
$write = null;
$except = null;
// 使用select函数来检测有无输入输出
$num_changed_sockets = stream_select($read, $write, $except, null);
foreach ($read as $sock) {
// 读取子进程的标准输出
if ($sock == $stdout) {
$line = fgets($sock);
if ($line === false) {
unset($read[array_search($sock, $read)]);
fclose($sock);
} else {
echo $line;
}
}
// 读取子进程的标准错误输出
if ($sock == $stderr) {
$line = fgets($sock);
if ($line === false) {
unset($read[array_search($sock, $read)]);
fclose($sock);
} else {
echo $line;
}
}
}
}
完整代码如下:
$socket = stream_socket_client('tcp://127.0.0.1:80', $errno, $errstr);
// 用于socket的标准输入输出
$stdin = $stdout = $stderr = $socket;
$pid = pcntl_fork();
if ($pid == -1) {
// fork失败
exit('Error: fork failed');
} elseif ($pid == 0) {
// 启动一个子进程,执行要执行的命令
exec('ls -l', $output, $return_var);
exit;
}
// 父进程中
// 开启非阻塞输入输出,并创建read的数组
stream_set_blocking($stdout, false);
stream_set_blocking($stderr, false);
$read = [$stdout, $stderr];
// 循环读取子进程的标准输入输出
while (!feof($stdout) || !feof($stderr)) {
$write = null;
$except = null;
// 使用select函数来检测有无输入输出
$num_changed_sockets = stream_select($read, $write, $except, null);
foreach ($read as $sock) {
// 读取子进程的标准输出
if ($sock == $stdout) {
$line = fgets($sock);
if ($line === false) {
unset($read[array_search($sock, $read)]);
fclose($sock);
} else {
echo $line;
}
}
// 读取子进程的标准错误输出
if ($sock == $stderr) {
$line = fgets($sock);
if ($line === false) {
unset($read[array_search($sock, $read)]);
fclose($sock);
} else {
echo $line;
}
}
}
}
总结
本文介绍了如何使用PHP的pcntl和stream_socket_client扩展实现非阻塞执行系统命令的方法。通过创建子进程来执行命令,并使用socket来进行非阻塞式的输出。如果对性能有较高要求的应用,可以考虑使用本方法来提高应用的性能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:php非阻塞执行系统命令 - Python技术站