php非阻塞执行系统命令

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日

相关文章

  • vue LogicFlow自定义边实现示例详解

    下面是对“vue LogicFlow自定义边实现示例详解”的完整攻略。 一、前言 Vue LogicFlow 是一个基于 Vue.js 的流程图库,它提供了许多丰富的功能和组件,例如节点、连线、锚点等。其中,连线是流程图中不可或缺的一个元素,Vue LogicFlow 可以自定义连线,本文将详细讲解如何实现自定义边。 二、实现自定义边 2.1 边类型定义 在…

    other 2023年6月25日
    00
  • gmpy2安装使用方法

    以下是“gmpy2安装使用方法的完整攻略”的详细说明,包括过程中的两个示例说明。 gmpy2安装使用方法 gmpy2是Python的一个高精度计算库,它可以处理大整数、大浮点数等高精度数据。以下是一份关于gmpy2的完整攻略。 1. gmpy2基础知识 在开始使用gmpy2之前,我们需要掌握一些基础知识,例如: Python的基础知识,包括Python的类型…

    other 2023年5月10日
    00
  • 一文搞懂Spring中的Bean作用域

    一文搞懂Spring中的Bean作用域 在Spring框架中,Bean作用域定义了在应用程序中创建和管理Bean实例的方式。Spring提供了多种Bean作用域,每种作用域都有不同的生命周期和可见性。本文将详细介绍Spring中的Bean作用域,并提供两个示例来说明其用法。 Singleton作用域 Singleton作用域是Spring中默认的作用域,它表…

    other 2023年8月19日
    00
  • linux shell将变量拼接到命令中

    当在Linux Shell中需要将变量拼接到命令中时,可以使用不同的方法来实现。下面是一个详细的攻略,其中包含两个示例说明。 方法一:使用变量替换 在Shell中,可以使用变量替换来将变量的值拼接到命令中。变量替换有两种形式:$variable和${variable}。下面是一个示例: #!/bin/bash # 定义一个变量 name=\"Joh…

    other 2023年8月8日
    00
  • Go语言字符串基础示例详解

    当然!下面是关于\”Go语言字符串基础示例详解\”的完整攻略: Go语言字符串基础示例详解 Go语言中的字符串是不可变的字节序列,使用UTF-8编码。以下是两个示例: 示例1:字符串的定义和基本操作 package main import \"fmt\" func main() { str := \"Hello, World!\…

    other 2023年8月19日
    00
  • css各种鼠标手型集合

    以下是详细讲解“CSS各种鼠标手型集合的完整攻略”的标准Markdown格式文本,包含两个示例说明: CSS各种鼠标手型集合攻略 在Web开发中,鼠标手型是一个重要的交互元素。CSS提供了各种鼠标手型,可以根据需要不同的鼠标手型。本攻略将介绍如何使用CSS设置各种鼠标手型。 步骤一:使用cursor属性 可以使用的cursor属性来设置鼠标手型。cursor…

    other 2023年5月10日
    00
  • Android Studio开发环境搭建教程详解

    Android Studio开发环境搭建教程详解 本教程将详细介绍如何搭建Android Studio开发环境。Android Studio是一款由Google开发的集成开发环境(IDE),用于开发Android应用程序。以下是搭建Android Studio开发环境的步骤: 步骤一:下载Android Studio 首先,您需要下载Android Stud…

    other 2023年7月27日
    00
  • Java Big Number操作BigInteger及BigDecimal类详解

    Java Big Number操作BigInteger及BigDecimal类详解 什么是Java Big Number? 在Java中数据类型是有限的,例如int、long等,这些数据类型能够表示的数字范围是有限的。但是在实际应用中,有时候需要进行精确计算,需要使用更大范围的数据类型来描述整数和小数,这时就需要用到Java Big Number。 Java…

    other 2023年6月26日
    00
合作推广
合作推广
分享本页
返回顶部