toknot/php-epoll

PHP 对 Linux epoll C API 的绑定。

0.2.1 2020-11-12 17:23 UTC

This package is auto-updated.

Last update: 2024-09-13 01:53:11 UTC


README

PHP 对 Linux epoll API 的绑定。

要求

  • PHP >= 7.4
  • PHP FFI 扩展可用
  • Linux > 2.6
  • toknot/ffi-extend>=0.1

安装

使用 composer install

composer require toknot/php-epoll

包含 composer 自动加载文件: ./vendor/autoload.php

参考

  • Epoll::__construct()

  • Epoll::create(int $flags)

    打开 epoll 文件描述符

  • Epoll::ctl(int $op, int $fd, EpollEvent $events): int

    epoll 文件描述符的控制接口

  • Epoll::wait(EpollEvent $event, int $maxevents, int $timeout, $sigmask = null): int

    在 epoll 文件描述符上等待 I/O 事件

  • Epoll::getFdno(resource $file, int $type): int

    从 PHP 资源文件描述符获取 ID

  • Epoll::lastErrno(): int

    获取最后错误代码

  • Epoll::lastError(): string

    获取最后错误消息

  • Epoll::ffi(): FFI

  • Epoll::initEvents($num): EpollEvent

  • EpollEvent::__construct(Epoll $epoll,$num)

  • EpollEvent::setEvent($event, $idx)

    设置 Epoll 事件

  • EpollEvent::setData($data, $idx)

    设置用户数据变量

  • EpollEvent::getEvents($idx): FFI\CData

简单示例

PHP 资源到文件描述符

$epoll = new Epoll();
$fp = fopen(__FILE__, 'rb');
$fdno = $epoll->getFdno($fp, Epoll::RES_TYPE_FILE);
$fdfp = fopen("php://fd/$fdno", 'rb');
echo fread($fdfp, 1024);

来自 man epoll 的 epoll 示例

const MAX_EVENTS = 10;
const EXIT_FAILURE = 1;

$epoll = new Epoll();
$ev = $epoll->initEvents(MAX_EVENTS);
$events = $epoll->initEvents();
$stream = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr);
$listen_sock = $epoll->getFdno($stream, Epoll::RES_TYPE_NET);

function perror($str) {
    fprintf(STDERR, $str);
}

$epollfd = $epoll->create(0);

$ev->setEvent(Epoll::EPOLLIN);
$ev->setData(['fd' => $listen_sock]);

if ($epoll->ctl(Epoll::EPOLL_CTL_ADD, $listen_sock, $ev) == -1) {
    perror("epoll_ctl: listen_sock");
    exit(EXIT_FAILURE);
}

for (;;) {
    $nfds = $epoll->wait($events, MAX_EVENTS, -1);
    if ($nfds == -1) {
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }

    for ($n = 0; $n < $nfds; ++$n) {
        if ($events[$n]->data->fd == $listen_sock) {
            $conn_sock = stream_socket_accept($stream);
            if (!$conn_sock) {
                perror("accept");
                exit(EXIT_FAILURE);
            }
            stream_set_blocking($conn_sock, false);
            $ev->setEvent(Epoll::EPOLLIN | Epoll::EPOLLET);
            $connFdno = $epoll->getFdno($conn_sock, Epoll::RES_TYPE_NET);
            $ev->setData(['fd' => $connFdno]);
            if ($epoll->ctl(Epoll::EPOLL_CTL_ADD, $connFdno,
                        $ev) == -1) {
                perror("epoll_ctl: conn_sock");
                exit(EXIT_FAILURE);
            }
        } else {
            do_use_fd($events[$n]->data->fd);
        }
    }
}