自定义Event Loop

EasySwoole支持自定义添加一个socket资源参与系统底层的事件调度循环,添加事件循环与swoole原生的EventLoop一致,这里只做简单介绍,扩展应用请参照swoole文档

  1. // 函数原型
  2. bool swoole_event_add(int $sock, mixed $read_callback, mixed $write_callback = null, int $flags = null);

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

参数1($sock)可以为以下三种类型:

  • int,就是文件描述符,包括swoole_client的socket,以及第三方扩展的socket(比如mysql)
  • stream资源,就是stream_socket_client/fsockopen 创建的资源
  • sockets资源,就是sockets扩展中 socket_create创建的资源,需要在编译时加入 ./configure —enable-sockets

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

参数4为事件类型的掩码,可选择关闭/开启可读可写事件,如SWOOLE_EVENT_READSWOOLE_EVENT_WRITE,或者SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE

回调函数

  • 在可读事件回调函数中必须使用freadrecv等函数读取Socket缓存区中的数据,否则事件会持续触发,如果不希望继续读取必须使用Swoole\Event::del移除事件监听
  • 在可写事件回调函数中,写入socket之后必须调用Swoole\Event::del移除事件监听,否则可写事件会持续触发
  • 执行freadsocekt_recvsocket_readSwoole\Client::recv返回false,并且错误码为EAGAIN时表示当前Socket接收缓存区内没有任何数据,这时需要加入可读监听等待EventLoop通知
  • 执行fwritesocket_writesocket_sendSwoole\Client::send操作返回false,并且错误码为EAGAIN时表示当前Socket发送缓存区已满,暂时不能发送数据。需要监听可写事件等待EventLoop通知

例子

例如在Conf/Event.php中的onWorkerStart事件中,添加以下代码:

  1. if($workerId == 0){
  2. $listener = stream_socket_server(
  3. "udp://0.0.0.0:9504",
  4. $error,
  5. $errMsg,
  6. STREAM_SERVER_BIND
  7. );
  8. if ($errMsg) {
  9. throw new \Exception("cluster server bind error on msg :{$errMsg}");
  10. } else {
  11. //加入event loop
  12. swoole_event_add($listener, function ($listener) {
  13. $data = stream_socket_recvfrom($listener, 9504, 0, $client);
  14. var_dump($data);
  15. stream_socket_sendto($listener, "hello", 0, $client());
  16. }
  17. );
  18. }
  19. }

启动EasySwoole,执行以下UDP客户端测试代码

  1. $client = new swoole_client(SWOOLE_SOCK_UDP);
  2. if (!$client->connect('127.0.0.1', 9504, -1))
  3. {
  4. exit("connect failed. Error: {$client->errCode}\n");
  5. }
  6. $client->send("hello\n");
  7. echo $client->recv();
  8. $client->close();

当客户端发送给服务端消息时,则会自动调用swoole_event_add中所注册的事件回调逻辑。