首页 Order Swoole4 正文

Swoole4 [协程高级] 系统API

金鹏头像 金鹏 Swoole4 2022-01-02 13:01:04 0 920
导读:Coroutine\System系统相关API的协程封装。此模块在v4.4.6正式版本后可用。大部分API基于AIO线程池实现。v4.4.6以前的版本,请使用C...

    Coroutine\System

    系统相关 API 的协程封装。此模块在 v4.4.6 正式版本后可用。大部分 API 基于 AIO 线程池实现。

    v4.4.6 以前的版本,请使用 Co 短名或 Swoole\Coroutine 调用,如: Co::sleepSwoole\Coroutine::sleep
    v4.4.6 及以后版本官方推荐使用Co\System::sleepSwoole\Coroutine\System::sleep
    此修改旨在规范命名空间,但同时也保证向下兼容 (也就是说 v4.4.6 版本以前的写法也是可以的,无需修改)

    方法

    statvfs()

    获取文件系统信息。

    Swoole 版本 >= v4.2.5 可用

    Swoole\Coroutine\System::statvfs(string $path): array|false
  • 参数

    • 功能:文件系统挂载的目录【如 /,可以使用 df 和 mount -l 命令获取】

    • 默认值:无

    • 其它值:无

    • string $path

  • 使用示例

Swoole\Coroutine\run(function () {
    var_dump(Swoole\Coroutine\System::statvfs('/'));
});

// array(11) {
//   ["bsize"]=>
//   int(4096)
//   ["frsize"]=>
//   int(4096)
//   ["blocks"]=>
//   int(61068098)
//   ["bfree"]=>
//   int(45753580)
//   ["bavail"]=>
//   int(42645728)
//   ["files"]=>
//   int(15523840)
//   ["ffree"]=>
//   int(14909927)
//   ["favail"]=>
//   int(14909927)
//   ["fsid"]=>
//   int(1002377915335522995)
//   ["flag"]=>
//   int(4096)
//   ["namemax"]=>
//   int(255)
// }

fread()

协程方式读取文件。

Swoole\Coroutine\System::fread(resource $handle, int $length = 0): string|false

v4.0.4 以下版本 fread 方法不支持非文件类型的 stream,如 STDINSocket,请勿使用 fread 操作此类资源。
v4.0.4 以上版本 fread 方法支持了非文件类型的 stream 资源,底层会自动根据 stream 类型选择使用 AIO 线程池或 EventLoop 实现。

  • 参数

    • 功能:读取的长度【默认为 0,表示读取文件的全部内容】

    • 默认值0

    • 其它值:无

    • 功能:文件句柄【必须是 fopen 打开的文件类型 stream 资源】

    • 默认值:无

    • 其它值:无

    • resource $handle

    • int $length

  • 返回值

    • 读取成功返回字符串内容,读取失败返回 false

  • 使用示例

$fp = fopen(__FILE__, "r");
Swoole\Coroutine\run(function () use ($fp)
{
    $r = Swoole\Coroutine\System::fread($fp);
    var_dump($r);
});

fwrite()

协程方式向文件写入数据。

Swoole\Coroutine\System::fwrite(resource $handle, string $data, int $length = 0): int|false

v4.0.4 以下版本 fwrite 方法不支持非文件类型的 stream,如 STDINSocket,请勿使用 fwrite 操作此类资源。
v4.0.4 以上版本 fwrite 方法支持了非文件类型的 stream 资源,底层会自动根据 stream 类型选择使用 AIO 线程池或 EventLoop 实现。

  • 参数

    • 功能:读取的长度【默认为 0,表示写入 $data 的全部内容,$length 必须小于 $data 的长度】

    • 默认值0

    • 其它值:无

    • 功能:要写入的数据内容【可以是文本或二进制数据】

    • 默认值:无

    • 其它值:无

    • 功能:文件句柄【必须是 fopen 打开的文件类型 stream 资源】

    • 默认值:无

    • 其它值:无

    • resource $handle

    • string $data

    • int $length

  • 返回值

    • 写入成功返回数据长度,读取失败返回 false

  • 使用示例

$fp = fopen(__DIR__ . "/test.data", "a+");
Swoole\Coroutine\run(function () use ($fp)
{
    $r = Swoole\Coroutine\System::fwrite($fp, "hello world\n", 5);
    var_dump($r);
});

fgets()

协程方式按行读取文件内容。

底层使用了 php_stream 缓存区,默认大小为 8192 字节,可使用 stream_set_chunk_size 设置缓存区尺寸。

Swoole\Coroutine\System::fgets(resource $handle): string|false

fgets 函数仅可用于文件类型的 stream 资源,Swoole 版本 >= v4.4.4 可用

  • 参数

    • 功能:文件句柄【必须是 fopen 打开的文件类型 stream 资源】

    • 默认值:无

    • 其它值:无

    • resource $handle

  • 返回值

    • 读取到 EOL\r\n)将返回一行数据,包括 EOL

    • 未读取到 EOL,但内容长度超过 php_stream 缓存区 8192 字节,将返回 8192 字节的数据,不包含 EOL

    • 达到文件末尾 EOF 时,返回空字符串,可用 feof 判断文件是否已读完

    • 读取失败返回 false,使用 swoole_last_error 函数获取错误码

  • 使用示例

$fp = fopen(__DIR__ . "/defer_client.php", "r");
Swoole\Coroutine\run(function () use ($fp)
{
    $r = Swoole\Coroutine\System::fgets($fp);
    var_dump($r);
});

    readFile()

    协程方式读取文件。

    Swoole\Coroutine\System::readFile(string $filename): string|false
  • 参数

    • 功能:文件名

    • 默认值:无

    • 其它值:无

    • string $filename

  • 返回值

    • 读取成功返回字符串内容,读取失败返回 false,可使用 swoole_last_error 获取错误信息

    • readFile 方法没有尺寸限制,读取的内容会存放在内存中,因此读取超大文件时可能会占用过多内存

  • 使用示例

$filename = __DIR__ . "/defer_client.php";
Swoole\Coroutine\run(function () use ($filename)
{
    $r = Swoole\Coroutine\System::readFile($filename);
    var_dump($r);
});

    writeFile()

    协程方式写入文件。

    Swoole\Coroutine\System::writeFile(string $filename, string $fileContent, int $flags): bool
  • 参数

    • 功能:写入的选项【默认会清空当前文件内容,可以使用 FILE_APPEND 表示追加到文件末尾】

    • 默认值:无

    • 其它值:无

    • 功能:写入到文件的内容【最大可写入 4M

    • 默认值:无

    • 其它值:无

    • 功能:文件名【必须有可写权限,文件不存在会自动创建。打开文件失败会立即返回 false

    • 默认值:无

    • 其它值:无

    • string $filename

    • string $fileContent

    • int $flags

  • 返回值

    • 写入成功返回 true

    • 写入失败返回 false

  • 使用示例

$filename = __DIR__ . "/defer_client.php";
Swoole\Coroutine\run(function () use ($filename)
{
    $w = Swoole\Coroutine\System::writeFile($filename, "hello swoole!");
    var_dump($w);
});

    sleep()

    进入等待状态。

    相当于 PHPsleep 函数,不同的是 Coroutine::sleep协程调度器实现的,底层会 yield 当前协程,让出时间片,并添加一个异步定时器,当超时时间到达时重新 resume 当前协程,恢复运行。

    使用 sleep 接口可以方便地实现超时等待功能。

    Swoole\Coroutine\System::sleep(float $seconds): void
  • 参数

    • 功能:睡眠的时间【必须大于 0,最大不得超过一天时间(86400 秒)】

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值:无

    • 其它值:无

    • float $seconds

  • 使用示例

$server = new Swoole\Http\Server("127.0.0.1", 9502);

$server->on('Request', function($request, $response) {
    //等待200ms后向浏览器发送响应
    Swoole\Coroutine\System::sleep(0.2);
    $response->end("<h1>Hello Swoole!</h1>");
});

$server->start();

    exec()

    执行一条 shell 指令。底层自动进行协程调度

    Swoole\Coroutine\System::exec(string $cmd): array
  • 参数

    • 功能:要执行的 shell 指令

    • 默认值:无

    • 其它值:无

    • string $cmd

  • 返回值

    • 执行失败返回 false,执行成功返回数组,包含了进程退出的状态码、信号、输出内容。

array(
    'code'   => 0,  // 进程退出的状态码
    'signal' => 0,  // 信号
    'output' => '', // 输出内容
);

使用示例  

Swoole\Coroutine\run(function() {
    $ret = Swoole\Coroutine\System::exec("md5sum ".__FILE__);
});

    gethostbyname()

    将域名解析为 IP。基于同步的线程池模拟实现,底层自动进行协程调度

    Swoole\Coroutine\System::gethostbyname(string $domain, int $family = AF_INET, float $timeout = -1): string|false
  • 参数

    • 功能:超时时间

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值-1

    • 其它值:无

    • 功能:域族【AF_INET 表示返回 IPv4 地址,使用 AF_INET6 时返回 IPv6 地址】

    • 默认值AF_INET

    • 其它值AF_INET6

    • 功能:域名

    • 默认值:无

    • 其它值:无

    • string $domain

    • int $family

    • float $timeout

  • 返回值

    • 成功返回域名对应的 IP 地址,失败返回 false,可使用 swoole_last_error 获取错误信息

array(
    'code'   => 0,  // 进程退出的状态码
    'signal' => 0,  // 信号
    'output' => '', // 输出内容
);
  • 扩展

    • 超时控制

      $timeout 参数可以控制协程等待的超时时间,在规定的时间内未返回结果,协程会立即返回 false 并继续向下执行。底层实现中会将该异步任务标记为 cancelgethostbyname 还是会在 AIO 线程池中继续执行。

      可修改 /etc/resolv.conf 设置 gethostbynamegetaddrinfo 底层 C 函数的超时时间。具体请参考 设置 DNS 解析超时和重试

  • 使用示例

Swoole\Coroutine\run(function () {
    $ip = Swoole\Coroutine\System::gethostbyname("www.baidu.com", AF_INET, 0.5);
    echo $ip;
});

    getaddrinfo()

    进行 DNS 解析,查询域名对应的 IP 地址。

    gethostbyname 不同,getaddrinfo 支持更多参数设置,而且会返回多个 IP 结果。

    Swoole\Coroutine\System::getaddrinfo(string $domain, int $family = AF_INET, int $socktype = SOCK_STREAM, int $protocol = STREAM_IPPROTO_TCP, string $service = null, float $timeout = -1): array|false
  • 参数

    • 功能:超时时间

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值-1

    • 其它值:无

    • 功能

    • 默认值:无

    • 其它值:无

    • 功能:协议

    • 默认值STREAM_IPPROTO_TCP

    • 其它值STREAM_IPPROTO_UDPSTREAM_IPPROTO_STCPSTREAM_IPPROTO_TIPC0

    • 功能:协议类型

    • 默认值SOCK_STREAM

    • 其它值SOCK_DGRAMSOCK_RAW

    • 功能:域族【AF_INET 表示返回 IPv4 地址,使用 AF_INET6 时返回 IPv6 地址】

    • 默认值:无

    • 其它值:无

    • 功能:域名

    • 默认值:无

    • 其它值:无

    • string $domain

    • int $family

      其他参数设置请参考 man getaddrinfo 文档

    • int $socktype

    • int $protocol

    • string $service

    • float $timeout

  • 返回值

    • 成功返回多个 IP 地址组成的数组,失败返回 false

  • 使用示例

Swoole\Coroutine\run(function () {
    $ips = Swoole\Coroutine\System::getaddrinfo("www.baidu.com");
    var_dump($ips);
});

    dnsLookup()

    域名地址查询。

    Coroutine\System::gethostbyname 不同,Coroutine\System::dnsLookup 是直接基于 UDP 客户端网络通信实现的,而不是使用 libc 提供的 gethostbyname 函数。

    Swoole 版本 >= v4.4.3 可用,底层会读取 /etc/resolve.conf 获取 DNS 服务器地址,目前仅支持 AF_INET(IPv4) 域名解析。Swoole 版本 >= v4.7 时可使用第三个参数来支持 AF_INET6(IPv6)

    Swoole\Coroutine\System::dnsLookup(string $domain, float $timeout = 5, int $type = AF_INET): string|false
  • 参数

    $type 参数在 Swoole 版本 >= v4.7 可用。

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值AF_INET

    • 其它值AF_INET6

    • 功能:超时时间

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值5

    • 其它值:无

    • 功能:域名

    • 默认值:无

    • 其它值:无

    • string $domain

    • float $timeout

    • int $type

  • 返回值

    • 解析成功返回对应的 IP 地址

    • 失败返回 false,可以使用 swoole_last_error 获取错误信息

  • 常见错误

    • SWOOLE_ERROR_DNSLOOKUP_RESOLVE_FAILED:此域名无法解析,查询失败

    • SWOOLE_ERROR_DNSLOOKUP_RESOLVE_TIMEOUT:解析超时,DNS 服务器可能存在故障,无法在规定的时间内返回结果

  • 使用示例

Swoole\Coroutine\run(function () {
    $ip = Swoole\Coroutine\System::dnsLookup("www.baidu.com");
    echo $ip;
});

wait()

对应原有的 Process::wait,不同的是此 API 是协程版本,会造成协程挂起,可替换 Swoole\Process::waitpcntl_wait 函数。

Swoole 版本 >= v4.5.0 可用

Swoole\Coroutine\System::wait(float $timeout = -1): array|false
  • 参数

    • 功能:超时时间,负数表示永不超时

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值-1

    • 其它值:无

    • float $timeout

  • 返回值

    • 操作成功会返回一个数组包含子进程的 PID、退出状态码、被哪种信号 KILL

    • 失败返回 false

每个子进程启动后,父进程必须都要派遣一个协程调用 wait()(或 waitPid()) 进行回收,否则子进程会变成僵尸进程,会浪费操作系统的进程资源。
如果使用了协程,必须是先创建进程,进程里面再开协程。而不是反过来,否则就是带着协程 fork 情况会非常复杂,导致底层很难处理。

  • 示例

use Swoole\Coroutine;
use Swoole\Coroutine\System;
use Swoole\Process;

$process = new Process(function () {
    echo 'Hello Swoole';
});
$process->start();

Coroutine\run(function () use ($process) {
    $status = System::wait();
    assert($status['pid'] === $process->pid);
    var_dump($status);
});

waitPid()

和上述 wait 方法基本一致,不同的是此 API 可以指定等待特定的进程

Swoole 版本 >= v4.5.0 可用

Swoole\Coroutine\System::waitPid(int $pid, float $timeout = -1): array|false
  • 参数

    • 功能:超时时间,负数表示永不超时

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值-1

    • 其它值:无

    • 功能:进程 id

    • 默认值-1 (表示任意进程,此时等价于 wait 方法)

    • 其它值:任意自然数

    • int $pid

    • float $timeout

  • 返回值

    • 操作成功会返回一个数组包含子进程的 PID、退出状态码、被哪种信号 KILL

    • 失败返回 false

每个子进程启动后,父进程必须都要派遣一个协程调用 wait()(或 waitPid()) 进行回收,否则子进程会变成僵尸进程,会浪费操作系统的进程资源。

  • 示例

use Swoole\Coroutine;
use Swoole\Coroutine\System;
use Swoole\Process;

$process = new Process(function () {
    echo 'Hello Swoole';
});
$process->start();

Coroutine\run(function () use ($process) {
    $status = System::waitPid($process->pid);
    var_dump($status);
});

waitSignal()

协程版本的信号监听器,会阻塞当前协程直到信号触发,可替换 Swoole\Process::signalpcntl_signal 函数。

Swoole 版本 >= v4.5.0 可用

Swoole\Coroutine\System::waitSignal(int $signo, float $timeout = -1): bool
  • 参数

    • 功能:超时时间,负数表示永不超时

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值-1

    • 其它值:无

    • 功能:信号类型

    • 默认值:无

    • 其它值:SIG 系列常量,如 SIGTERM, SIGKILL

    • int $signo

    • float $timeout

  • 返回值

    • 收到信号返回 true

    • 超时未收到信号返回 false

  • 示例

use Swoole\Coroutine;
use Swoole\Coroutine\System;
use Swoole\Process;

$process = new Process(function () {
    Coroutine\run(function () {
        $bool = System::waitSignal(SIGUSR1);
        var_dump($bool);
    });
});
$process->start();
sleep(1);
$process::kill($process->pid, SIGUSR1);

waitEvent()

协程版本的信号监听器,会阻塞当前协程直到信号触发。等待 IO 事件,可替换 swoole_event 相关函数。

Swoole 版本 >= v4.5 可用

Swoole\Coroutine\System::waitEvent(mixed $socket, int $events = SWOOLE_EVENT_READ, float $timeout = -1): int | false
  • 参数

    • 功能:超时时间,负数表示永不超时

    • 值单位:秒,最小精度为毫秒(0.001 秒)

    • 默认值-1

    • 其它值:无

    • 功能:事件类型

    • 默认值SWOOLE_EVENT_READ

    • 其它值SWOOLE_EVENT_WRITESWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE

    • 功能:文件描述符 (任何可以转化为 fd 的类型,如 Socket 对象,资源等等)

    • 默认值:无

    • 其它值:无

    • mixed $socket

    • int $events

    • float $timeout

  • 返回值

    • 返回触发的事件类型的和 (可能是多个位), 和参数 $events 传入的值有关

    • 失败返回 false,可以使用 swoole_last_error 获取错误信息

  • 示例

同步阻塞的代码通过该 API 即可变为协程非阻塞

use Swoole\Coroutine;

Coroutine\run(function () {
    $client = stream_socket_client('tcp://www.qq.com:80', $errno, $errstr, 30);
    $events = Coroutine::waitEvent($client, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE);
    assert($events === SWOOLE_EVENT_WRITE);
    fwrite($client, "GET / HTTP/1.1\r\nHost: www.qq.com\r\n\r\n");
    $events = Coroutine::waitEvent($client, SWOOLE_EVENT_READ);
    assert($events === SWOOLE_EVENT_READ);
    $response = fread($client, 8192);
    echo $response;
});


本文地址:https://www.jinpeng.work/?id=91
若非特殊说明,文章均属本站原创,转载请注明原链接。
广告3

欢迎 发表评论:

  • 请填写验证码

日历

«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930

控制面板

您好,欢迎到访网站!
  查看权限
广告2

退出请按Esc键