php非阻塞执行系统命令

yizhihongxing

PHP非阻塞执行系统命令

在Web开发中,有时候需要在PHP脚本中执行一些后台操作或系统命令。常见的方法是使用PHP提供的exec()shell_exec()等函数。但是这些函数都是阻塞式的,也就是说当命令执行时,PHP脚本会一直等待,直到命令执行完成后才继续执行下面的代码。如果要执行的命令比较耗时,就会导致整个应用的性能下降。

为了解决这个问题,可以使用PHP的非阻塞执行命令的技术。在这篇文章中,我们将介绍如何使用PHP的扩展库pcntlstream_socket_client实现非阻塞执行系统命令。

安装PCNTL扩展

PCNTL(Process Control)扩展是PHP的一个内置扩展,在不同的发行版下可能需要单独安装。在安装之前,需要确认PHP版本和架构,安装好PCNTL后,在php.ini文件中新增扩展配置:

extension=pcntl.so

执行非阻塞命令

下面是使用pcntl和stream_socket_client执行非阻塞命令的步骤:

  1. 创建一个socket客户端连接:
$socket = stream_socket_client('tcp://127.0.0.1:80', $errno, $errstr);
// 用于socket的标准输入输出
$stdin = $stdout = $stderr = $socket;
  1. 启动一个子进程,执行系统命令:
$pid = pcntl_fork();
if ($pid == -1) {
    // fork失败
    exit('Error: fork failed');
} elseif ($pid == 0) {
    // 启动一个子进程,执行要执行的命令
    exec('ls -l', $output, $return_var);
    exit;
}
  1. 在父进程中,监听子进程的输出并进行相关处理:
// 开启非阻塞输入输出,并创建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技术站

(0)
上一篇 2023年3月28日
下一篇 2023年3月28日

相关文章

  • 关于java:为charset.forname(string)编码charsetnames

    关于Java: charset.forName(String)编码charsetNames的完整攻略 在Java中,我们可以使用Charset.forName(String)方法来获取指定编码名称的Charset对象。该方法接受一个字符串参数,该参数指定要获取的编码名称。在本攻略中,我们将详细讲解如何使用Charset.forName(String)方法来获…

    other 2023年5月9日
    00
  • LocalStorage封装一次解决方法示例

    接下来我会分步骤详细讲解LocalStorage封装一次解决方法示例的完整攻略: 思路 定义一个封装对象,该对象可以支持get、set、remove方法。 使用JSON.stringify将对象转换为字符串,使用JSON.parse将字符串还原为对象。这样可以将JavaScript对象存储到localStorage中。 添加了一个过期时间的功能。如果过期时间…

    other 2023年6月25日
    00
  • 前端笔记——如何控制表单控件中的disabled

    前端笔记——如何控制表单控件中的disabled 在前端开发中,表单是一个必不可少的组件,而在表单中,有时需要控制一些表单控件的禁用状态,以达到更好的用户体验和工作流程。本篇文章将介绍如何通过前端代码控制表单控件中的disabled。 什么是disabled属性 在HTML中,每个表单控件(例如文本框、下拉列表、单选框、复选框等)都可以设置一个disable…

    其他 2023年3月28日
    00
  • serv-u配置说明(虚拟路径、网络驱动器、个人文件夹 数据…

    Serv-U配置说明(虚拟路径、网络驱动器、个人文件夹 数据) Serv-U是一个流行的FTP服务器应用程序,它提供了一系列高级功能,使得文件共享变得更加简单和易用。在本文中,我们将详细介绍Serv-U如何配置虚拟路径、网络驱动器和个人文件夹的数据。 配置虚拟路径 虚拟路径是指指向服务器上某个实际目录的逻辑路径。在Serv-U中,为了节省磁盘空间,我们可以将…

    其他 2023年3月28日
    00
  • 获取对象的key、value及长度

    当然,我很乐意为您提供关于“获取对象的key、value及长度”的完整攻略。以下是详细的步骤说明: 步骤说明 在JavaScript中,可以使用以下方法获取对象的key、及长度: 获取的 使用Object.keys()方法可以获取对象的所有key。以下是使用Object.keys()方法获取对象key的步骤: 定义一个对象。 使用Object.keys()方…

    other 2023年5月9日
    00
  • Ext2 文件系统的硬盘布局

    Ext2 文件系统的硬盘布局 Ext2(第二扩展文件系统)是一种用于Linux操作系统的文件系统。它定义了硬盘上数据的组织方式和存储结构。下面是Ext2文件系统的硬盘布局的详细说明: 引导扇区(Boot Sector) 硬盘的第一个扇区被称为引导扇区,它包含了引导加载程序(boot loader)的代码。引导加载程序负责加载操作系统并将控制权转交给它。在Ex…

    other 2023年9月5日
    00
  • 魅族MX3怎么建立桌面文件夹 魅族MX3桌面布局教程图文详解

    魅族MX3怎么建立桌面文件夹 魅族MX3是一款功能强大的手机,它允许用户在桌面上创建文件夹来整理应用程序。下面是建立桌面文件夹的详细攻略: 长按空白的桌面区域,直到屏幕上出现一个菜单。 在菜单中选择“添加文件夹”选项。 一个新的文件夹图标将会出现在桌面上。 点击新建的文件夹图标,进入文件夹。 在文件夹中,长按空白的区域,直到屏幕上出现一个菜单。 在菜单中选择…

    other 2023年9月5日
    00
  • usb协议基础知识

    USB协议基础知识 什么是USB协议 USB全称为Universal Serial Bus(通用串行总线),是一种广泛应用于连接计算机及外部设备的接口标准。USB协议是一个计算机标准,规定了连接电脑和外围设备之间的通信规则。它为计算机和各类设备(包括键盘、鼠标、音频设备、视频设备、打印机等)的连接提供了一种常用的、低成本、易于使用的接口,便于实现各类设备的功…

    其他 2023年3月28日
    00
合作推广
合作推广
分享本页
返回顶部