首页 Order Swoole4 正文

Swoole4 事件管理

金鹏头像 金鹏 Swoole4 2022-01-02 15:01:48 0 985
导读:EventSwoole扩展还提供了直接操作底层epoll/kqueue事件循环的接口。可将其他扩展创建的socket,PHP代码中stream/socket扩展创建的...

Event

Swoole 扩展还提供了直接操作底层 epoll/kqueue 事件循环的接口。可将其他扩展创建的 socketPHP 代码中 stream/socket 扩展创建的 socket 等加入到 SwooleEventLoop 中, 否则第三方的 $fd 如果是同步 IO 会导致 Swoole 的 EventLoop 得不到执行,参考案例

Event 模块比较底层,是 epoll 的初级封装,使用者最好有 IO 多路复用编程经验。

事件优先级

  1. 通过 Process::signal 设置的信号处理回调函数

  2. 通过 Timer::tickTimer::after 设置的定时器回调函数

  3. 通过 Event::defer 设置的延迟执行函数

  4. 通过 Event::cycle 设置的周期回调函数

方法

add()

将一个 socket 加入到底层的 reactor 事件监听中。此函数可以用在 ServerClient 模式下。

Swoole\Event::add(mixed $sock, callable $read_callback, callable $write_callback = null, int $flags = null): bool

Server 程序中使用时,必须在 Worker 进程启动后使用。在 Server::start 之前不得调用任何异步 IO 接口

  • 参数

    • 功能:事件类型的掩码【可选择关闭 / 开启可读可写事件,如 SWOOLE_EVENT_READSWOOLE_EVENT_WRITE 或者 SWOOLE_EVENT_READ|SWOOLE_EVENT_WRITE

    • 默认值:无

    • 其它值:无

    • 功能:为可写事件回调函数【此参数可以是字符串函数名、对象 + 方法、类静态方法或匿名函数,当此 socket 可读或者可写时回调指定的函数。】

    • 默认值:无

    • 其它值:无

    • 功能:可读事件回调函数

    • 默认值:无

    • 其它值:无

    • 功能:文件描述符、stream 资源、sockets 资源、object

    • 默认值:无

    • 其它值:无

    • mixed $sock

    • callable $read_callback

    • callable $write_callback

    • int $flags

  • $sock 4 种类型

类型说明
int文件描述符,包括 Swoole\Client->$sockSwoole\Process->$pipe 或者其他 fd
stream 资源stream_socket_client/fsockopen 创建的资源
sockets 资源sockets 扩展中 socket_create 创建的资源,需要在编译时加入 ./configure --enable-sockets
objectSwoole\ProcessSwoole\Client,底层自动转换为 UnixSocketProcess)或客户端连接的 socketSwoole\Client
  • 返回值

    使用 Swoole\Event::addsocket 加入到事件监听后,底层会自动将该 socket 设置为非阻塞模式

    • 添加事件监听成功成功返回 true

    • 添加失败返回 false,请使用 swoole_last_error 获取错误码

    • 已添加过的 socket 不能重复添加,可以使用 swoole_event_set 修改 socket 对应的回调函数和事件类型

  • 使用示例

$fp = stream_socket_client("tcp://www.qq.com:80", $errno, $errstr, 30);
fwrite($fp,"GET / HTTP/1.1\r\nHost: www.qq.com\r\n\r\n");

Swoole\Event::add($fp, function($fp) {
    $resp = fread($fp, 8192);
    //socket处理完成后,从epoll事件中移除socket
    Swoole\Event::del($fp);
    fclose($fp);
});
echo "Finish\n";  //Swoole\Event::add 不会阻塞进程,这行代码会顺序执行
  • 回调函数

    • 在可读 ($read_callback) 事件回调函数中必须使用 freadrecv 等函数读取 socket 缓存区中的数据,否则事件会持续触发,如果不希望继续读取必须使用 Swoole\Event::del 移除事件监听

    • 在可写 ($write_callback) 事件回调函数中,写入 socket 之后必须调用 Swoole\Event::del 移除事件监听,否则可写事件会持续触发

    • 执行 freadsocekt_recvsocket_readSwoole\Client::recv 返回 false,并且错误码为 EAGAIN 时表示当前 socket 接收缓存区内没有任何数据,这时需要加入可读监听等待 EventLoop 通知

    • 执行 fwritesocket_writesocket_sendSwoole\Client::send 操作返回 false,并且错误码为 EAGAIN 时表示当前 socket 发送缓存区已满,暂时不能发送数据。需要监听可写事件等待 EventLoop 通知

set()

修改事件监听的回调函数和掩码。

Swoole\Event::set($fd, mixed $read_callback, mixed $write_callback, int $flags): bool
  • 参数

    注意如果监听了 SWOOLE_EVENT_READ 事件,而当前并未设置 read_callback,底层会直接返回 false,添加失败。SWOOLE_EVENT_WRITE 同理。

    • 参数与 Event::add 完全相同。如果传入 $fdEventLoop 中不存在返回 false

    • $read_callback 不为 null 时,将修改可读事件回调函数为指定的函数

    • $write_callback 不为 null 时,将修改可写事件回调函数为指定的函数

    • $flags 可关闭 / 开启,可写(SWOOLE_EVENT_READ)和可读(SWOOLE_EVENT_WRITE)事件的监听

  • 状态变更

    • 使用 Event::addEvent::set 设置了可读事件回调,但并未监听 SWOOLE_EVENT_READ 可读事件,这时底层仅保存回调函数的信息,并不会产生任何事件回调。

    • 可以使用 Event::set($fd, null, null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE),修改监听的事件类型,这时底层会触发可读事件。

  • 释放回调函数

注意 Event::set 只能替换回调函数,但并不能释放事件回调函数。如:Event::set($fd, null, null, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE),参数中传入的 read_callbackwrite_callbacknull,表示不对 Event::add 设置的回调函数进行修改,而不是将事件回调函数设为 null

只有调用 Event::del 清除事件监听时,底层才会释放 read_callbackwrite_callback 事件回调函数。

isset()

检测传入的 $fd 是否已加入了事件监听。

Swoole\Event::isset(mixed $fd, int $events = SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE): bool
  • 参数

    • 功能:检测的事件类型

    • 默认值:无

    • 其它值:无

    • 功能:任意的 socket 文件描述符【参考 Event::add 文档】

    • 默认值:无

    • 其它值:无

    • mixed $fd

    • int $events

  • $events

事件类型说明
SWOOLE_EVENT_READ是否监听了可读事件
SWOOLE_EVENT_WRITE是否监听了可写事件
SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE监听可读或可写事件
  • 使用示例

use Swoole\Event;

$fp = stream_socket_client("tcp://www.qq.com:80", $errno, $errstr, 30);
fwrite($fp,"GET / HTTP/1.1\r\nHost: www.qq.com\r\n\r\n");

Event::add($fp, function($fp) {
    $resp = fread($fp, 8192);
    Swoole\Event::del($fp);
    fclose($fp);
}, null, SWOOLE_EVENT_READ);
var_dump(Event::isset($fp, SWOOLE_EVENT_READ)); //返回 true
var_dump(Event::isset($fp, SWOOLE_EVENT_WRITE)); //返回 false
var_dump(Event::isset($fp, SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE)); //返回 true

write()

用于 PHP 自带 stream/sockets 扩展创建的 socket,使用 fwrite/socket_send 等函数向对端发送数据。当发送的数据量较大,socket 写缓存区已满,就会发送阻塞等待或者返回 EAGAIN 错误。

Event::write 函数可以将 stream/sockets 资源的数据发送变成异步的,当缓冲区满了或者返回 EAGAIN,Swoole 底层会将数据加入到发送队列,并监听可写。socket 可写时 Swoole 底层会自动写入

Swoole\Event::write(mixed $fd, miexd $data): bool
  • 参数

    • 功能:要发送的数据 【发送数据的长度不得超过 Socket 缓存区尺寸】

    • 默认值:无

    • 其它值:无

    • 功能:任意的 socket 文件描述符【参考 Event::add 文档】

    • 默认值:无

    • 其它值:无

    • mixed $fd

    • miexd $data

Event::write 不能用于 SSL/TLS 等有隧道加密的 stream/sockets 资源
Event::write 操作成功后,会自动将该 $socket 设置为非阻塞模式

  • 使用示例

use Swoole\Event;

$fp = stream_socket_client('tcp://127.0.0.1:9501');
$data = str_repeat('A', 1024 * 1024*2);

Event::add($fp, function($fp) {
     echo fread($fp);
});

Event::write($fp, $data);

SOCKET 缓存区已满后,Swoole 的底层逻辑

持续写入 SOCKET 如果对端读取不够快,那 SOCKET 缓存区会塞满。Swoole 底层会将数据存到内存缓存区中,直到可写事件触发再写入 SOCKET

如果内存缓存区也被写满了,此时 Swoole 底层会抛出 pipe buffer overflow, reactor will block. 错误,并进入阻塞等待。

缓存塞满返回 false 是原子操作,只会出现全部写入成功或者全部失败

del()

reactor 中移除监听的 socketEvent::del 应当与 Event::add 成对使用。

Swoole\Event::del(mixed $sock): bool

必须在 socketclose 操作前使用 Event::del 移除事件监听,否则可能会产生内存泄漏

  • 参数

    • 功能socket 的文件描述符

    • 默认值:无

    • 其它值:无

    • mixed $sock

exit()

退出事件轮询。

此函数仅在 Client 程序中有效

Swoole\Event::exit(): void

defer()

在下一个事件循环开始时执行函数。

Swoole\Event::defer(mixed $callback_function);

Event::defer 的回调函数会在当前 EventLoop 的事件循环结束、下一次事件循环开始前执行。

  • 参数

    • 功能:时间到期后所执行的函数 【必须是可以调用的。回调函数不接受任何参数,可以使用匿名函数的 use 语法传递参数到回调函数中;在 $callback_function 函数执行过程中添加新的 defer 任务,仍然会在本轮事件循环内执行完成】

    • 默认值:无

    • 其它值:无

    • mixed $callback_function

  • 使用示例

Swoole\Event::defer(function(){
     echo "After EventLoop\n"; 
});

cycle()

定义事件循环周期执行函数。此函数会在每一轮事件循环结束时调用。

Swoole\Event::cycle(callable $callback, bool $before = false): bool
  • 参数

    • 功能:在 EventLoop 之前调用该函数

    • 默认值:无

    • 其它值:无

    • 功能:要设置的回调函数 【$callbacknull 时表示清除 cycle 函数,已设置 cycle 函数,重新设置时会覆盖上一次的设定】

    • 默认值:无

    • 其它值:无

    • callable $callback_function

    • bool $before

可以同时存在 before=truebefore=false 两个回调函数。

  • 使用示例

Swoole\Timer::tick(2000, function ($id) {
    var_dump($id);
});

Swoole\Event::cycle(function () {
    echo "hello [1]\n";
    Swoole\Event::cycle(function () {
        echo "hello [2]\n";
        Swoole\Event::cycle(null);
    });
});

wait()

启动事件监听。

请将此函数放置于 PHP 程序末尾

Swoole\Event::wait();
  • 使用示例

Swoole\Timer::tick(1000, function () {
     echo "hello\n"; 
}); 

Swoole\Event::wait();

dispatch()

启动事件监听。

仅执行一次 reactor->wait 操作,在 Linux 平台下相当手动调用一次 epoll_wait。与 Event::dispatch 不同的是,Event::wait 在底层内部维持了循环。

Swoole\Event::dispatch();
  • 使用示例

while(true)
{
    Event::dispatch();
}

此函数的目的是兼容一些框架,如 amp,它在框架内部自行控制 reactor 的循环,而使用 Event::wait,Swoole 底层维持了控制权,就无法让出给框架方。


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

欢迎 发表评论:

  • 请填写验证码

日历

«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930

控制面板

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

退出请按Esc键