多端口混合协议

更多的信息,请参考Swoole增加监听的端口多端口混合协议

为了使我们的主服务器能支持除HTTPWebSocket外的更多协议,我们引入了Swoole多端口混合协议特性,在LaravelS中称为Socket。现在,可以很方便地在Laravel上构建TCP/UDP应用。

  1. 创建Socket处理类,继承Hhxsv5\LaravelS\Swoole\Socket\{TcpSocket|UdpSocket|Http|WebSocket}

    1. namespace App\Sockets;
    2. use Hhxsv5\LaravelS\Swoole\Socket\TcpSocket;
    3. use Swoole\Server;
    4. class TestTcpSocket extends TcpSocket
    5. {
    6. public function onConnect(Server $server, $fd, $reactorId)
    7. {
    8. \Log::info('New TCP connection', [$fd]);
    9. $server->send($fd, 'Welcome to LaravelS.');
    10. }
    11. public function onReceive(Server $server, $fd, $reactorId, $data)
    12. {
    13. \Log::info('Received data', [$fd, $data]);
    14. $server->send($fd, 'LaravelS: ' . $data);
    15. if ($data === "quit\r\n") {
    16. $server->send($fd, 'LaravelS: bye' . PHP_EOL);
    17. $server->close($fd);
    18. }
    19. }
    20. public function onClose(Server $server, $fd, $reactorId)
    21. {
    22. \Log::info('Close TCP connection', [$fd]);
    23. $server->send($fd, 'Goodbye');
    24. }
    25. }

    这些连接和主服务器上的HTTP/WebSocket连接共享Worker进程,因此可以在这些事件回调中使用LaravelS提供的异步任务投递SwooleTable、Laravel提供的组件如DBEloquent等。同时,如果需要使用该协议端口的Swoole\Server\Port对象,只需要像如下代码一样访问Socket类的成员swoolePort即可。

    1. public function onReceive(Server $server, $fd, $reactorId, $data)
    2. {
    3. $port = $this->swoolePort; // 获得`Swoole\Server\Port`对象
    4. }
    1. namespace App\Http\Controllers;
    2. class TestController extends Controller
    3. {
    4. public function test()
    5. {
    6. /**@var \Swoole\Http\Server|\Swoole\WebSocket\Server $swoole */
    7. $swoole = app('swoole');
    8. // $swoole->ports:遍历所有Port对象,https://wiki.swoole.com/#/server/properties?id=ports
    9. $port = $swoole->ports[1]; // 获得`Swoole\Server\Port`对象,$port[0]是主服务器的端口
    10. foreach ($port->connections as $fd) { // 遍历所有连接
    11. // $swoole->send($fd, 'Send tcp message');
    12. // if($swoole->isEstablished($fd)) {
    13. // $swoole->push($fd, 'Send websocket message');
    14. // }
    15. }
    16. }
    17. }
  2. 注册套接字。

    1. // 修改文件 config/laravels.php
    2. // ...
    3. 'sockets' => [
    4. [
    5. 'host' => '127.0.0.1',
    6. 'port' => 5291,
    7. 'type' => SWOOLE_SOCK_TCP,// 支持的嵌套字类型:https://wiki.swoole.com/#/consts?id=socket-%e7%b1%bb%e5%9e%8b
    8. 'settings' => [// Swoole可用的配置项:https://wiki.swoole.com/#/server/port?id=%e5%8f%af%e9%80%89%e5%8f%82%e6%95%b0
    9. 'open_eof_check' => true,
    10. 'package_eof' => "\r\n",
    11. ],
    12. 'handler' => \App\Sockets\TestTcpSocket::class,
    13. 'enable' => true, // 是否启用,默认为true
    14. ],
    15. ],

    关于心跳配置,只能设置在主服务器上,不能配置在套接字上,但套接字会继承主服务器的心跳配置。

    对于TCP协议,dispatch_mode选项设为1/3时,底层会屏蔽onConnect/onClose事件,原因是这两种模式下无法保证onConnect/onClose/onReceive的顺序。如果需要用到这两个事件,请将dispatch_mode改为2/4/5参考

    1. 'swoole' => [
    2. //...
    3. 'dispatch_mode' => 2,
    4. //...
    5. ];
  3. 测试。

  • TCP:telnet 127.0.0.1 5291

  • UDP:Linux下 echo "Hello LaravelS" > /dev/udp/127.0.0.1/5292

  1. 其他协议的注册示例。

    • UDP
    1. 'sockets' => [
    2. [
    3. 'host' => '0.0.0.0',
    4. 'port' => 5292,
    5. 'type' => SWOOLE_SOCK_UDP,
    6. 'settings' => [
    7. 'open_eof_check' => true,
    8. 'package_eof' => "\r\n",
    9. ],
    10. 'handler' => \App\Sockets\TestUdpSocket::class,
    11. ],
    12. ],
    • Http
    1. 'sockets' => [
    2. [
    3. 'host' => '0.0.0.0',
    4. 'port' => 5293,
    5. 'type' => SWOOLE_SOCK_TCP,
    6. 'settings' => [
    7. 'open_http_protocol' => true,
    8. ],
    9. 'handler' => \App\Sockets\TestHttp::class,
    10. ],
    11. ],
    • WebSocket:主服务器必须开启WebSocket,即需要将websocket.enable置为true
    1. 'sockets' => [
    2. [
    3. 'host' => '0.0.0.0',
    4. 'port' => 5294,
    5. 'type' => SWOOLE_SOCK_TCP,
    6. 'settings' => [
    7. 'open_http_protocol' => true,
    8. 'open_websocket_protocol' => true,
    9. ],
    10. 'handler' => \App\Sockets\TestWebSocket::class,
    11. ],
    12. ],