hyperf / socketio-server
Socket.io implementation for hyperf
Fund package maintenance!
Open Collective
hyperf.wiki/#/zh-cn/donate
Installs: 76 710
Dependents: 5
Suggesters: 0
Security: 0
Stars: 22
Watchers: 5
Forks: 6
Open Issues: 12
Requires
- php: >=8.1
- ext-json: *
- ext-redis: *
- hyperf/codec: ~3.1.0
- hyperf/collection: ~3.1.0
- hyperf/di: ~3.1.0
- hyperf/redis: ~3.1.0
- hyperf/websocket-server: ~3.1.0
- psr/container: ^1.0 || ^2.0
Suggests
- hyperf/command: Required to use RemoveRedisGarbage command
- hyperf/nsq: Required to use RedisNsqAdapter
- hyperf/session: Required to use session
- mix/redis-subscriber: Suggest to use RedisAdapter (^3.0.4)
Conflicts
- mix/redis-subscriber: <3.0.4
- 3.1.x-dev
- dev-master / 3.1.x-dev
- v3.1.42
- v3.1.37
- v3.1.32
- v3.1.27
- v3.1.23
- v3.1.19
- v3.1.15
- v3.1.6
- v3.1.1
- v3.1.0
- v3.1.0-rc.5
- v3.1.0-rc.4
- v3.1.0-beta.2
- v3.1.0-alpha.2
- v3.1.0-alpha.1
- 3.0.x-dev
- v3.0.48
- v3.0.47
- v3.0.38
- v3.0.37
- v3.0.25
- v3.0.18
- v3.0.16
- v3.0.15
- v3.0.6
- v3.0.1
- v3.0.0
- v3.0.0-rc.13
- v3.0.0-rc.8
- v3.0.0-rc.4
- v3.0.0-rc.3
- v3.0.0-rc.1
- v3.0.0-beta.10
- v3.0.0-beta.9
- v3.0.0-beta.8
- v3.0.0-beta.5
- v3.0.0-beta.2
- v3.0.0-beta.1
- v3.0.0-alpha.11
- v3.0.0-alpha.9
- v3.0.0-alpha.7
- v3.0.0-alpha.6
- v3.0.0-alpha.1
- 2.2.x-dev
- v2.2.41
- v2.2.40
- v2.2.33
- v2.2.30
- v2.2.19
- v2.2.8
- v2.2.4
- v2.2.1
- v2.2.0
- v2.2.0-beta2
- v2.2.0-beta1
- 2.1.x-dev
- v2.1.13
- v2.1.1
- v2.1.0
- v2.1.0-beta1
- 2.0.x-dev
- v2.0.26
- v2.0.25
- v2.0.13
- v2.0.11
- v2.0.10
- v2.0.8
- v2.0.7
- v2.0.6
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.0
- 1.1.x-dev
- v1.1.32
- v1.1.31
- v1.1.0
This package is auto-updated.
Last update: 2024-10-25 03:44:33 UTC
README
Socket.io是一款非常流行的应用层实时通讯协议和框架,可以轻松实现应答、分组、广播。hyperf/socketio-server支持了Socket.io的WebSocket传输协议。
安装
composer require hyperf/socketio-server
hyperf/socketio-server 是基于WebSocket实现的,请确保服务端已经添加了WebSocket服务配置。
[ 'name' => 'socket-io', 'type' => Server::SERVER_WEBSOCKET, 'host' => '0.0.0.0', 'port' => 9502, 'sock_type' => SWOOLE_SOCK_TCP, 'callbacks' => [ SwooleEvent::ON_HAND_SHAKE => [Hyperf\WebSocketServer\Server::class, 'onHandShake'], SwooleEvent::ON_MESSAGE => [Hyperf\WebSocketServer\Server::class, 'onMessage'], SwooleEvent::ON_CLOSE => [Hyperf\WebSocketServer\Server::class, 'onClose'], ], ],
快速开始
服务端
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\SocketIOServer\Annotation\Event; use Hyperf\SocketIOServer\Annotation\SocketIONamespace; use Hyperf\SocketIOServer\BaseNamespace; use Hyperf\SocketIOServer\Socket; use Hyperf\Codec\Json; /** * @SocketIONamespace("/") */ class WebSocketController extends BaseNamespace { /** * @Event("event") * @param string $data */ public function onEvent(Socket $socket, $data) { // 应答 return 'Event Received: ' . $data; } /** * @Event("join-room") * @param string $data */ public function onJoinRoom(Socket $socket, $data) { // 将当前用户加入房间 $socket->join($data); // 向房间内其他用户推送(不含当前用户) $socket->to($data)->emit('event', $socket->getSid() . "has joined {$data}"); // 向房间内所有人广播(含当前用户) $this->emit('event', 'There are ' . count($socket->getAdapter()->clients($data)) . " players in {$data}"); } /** * @Event("say") * @param string $data */ public function onSay(Socket $socket, $data) { $data = Json::decode($data); $socket->to($data['room'])->emit('event', $socket->getSid() . " say: {$data['message']}"); } }
每个 socket 会自动加入以自己
sid
命名的房间($socket->getSid()
),发送私聊信息就推送到对应sid
即可。
框架会触发
connect
和disconnect
两个事件。
客户端
由于服务端只实现了WebSocket通讯,所以客户端要加上 {transports:["websocket"]}
。
<script src="https://cdn.bootcdn.net/ajax/libs/socket.io/2.3.0/socket.io.js"></script> <script> var socket = io('ws://127.0.0.1:9502', { transports: ["websocket"] }); socket.on('connect', data => { socket.emit('event', 'hello, hyperf', console.log); socket.emit('join-room', 'room1', console.log); setInterval(function () { socket.emit('say', '{"room":"room1", "message":"Hello Hyperf."}'); }, 1000); }); socket.on('event', console.log); </script>
API 清单
<?php function onConnect(\Hyperf\SocketIOServer\Socket $socket){ // sending to the client $socket->emit('hello', 'can you hear me?', 1, 2, 'abc'); // sending to all clients except sender $socket->broadcast->emit('broadcast', 'hello friends!'); // sending to all clients in 'game' room except sender $socket->to('game')->emit('nice game', "let's play a game"); // sending to all clients in 'game1' and/or in 'game2' room, except sender $socket->to('game1')->to('game2')->emit('nice game', "let's play a game (too)"); // WARNING: `$socket->to($socket->getSid())->emit()` will NOT work, as it will send to everyone in the room // named `$socket->getSid()` but the sender. Please use the classic `$socket->emit()` instead. // sending with acknowledgement $reply = $socket->emit('question', 'do you think so?')->reply(); // sending without compression $socket->compress(false)->emit('uncompressed', "that's rough"); $io = \Hyperf\Context\ApplicationContext::getContainer()->get(\Hyperf\SocketIOServer\SocketIO::class); // sending to all clients in 'game' room, including sender $io->in('game')->emit('big-announcement', 'the game will start soon'); // sending to all clients in namespace 'myNamespace', including sender $io->of('/myNamespace')->emit('bigger-announcement', 'the tournament will start soon'); // sending to a specific room in a specific namespace, including sender $io->of('/myNamespace')->to('room')->emit('event', 'message'); // sending to individual socketid (private message) $io->to('socketId')->emit('hey', 'I just met you'); // sending to all clients on this node (when using multiple nodes) $io->local->emit('hi', 'my lovely babies'); // sending to all connected clients $io->emit('an event sent to all connected clients'); };
进阶教程
设置 Socket.io 命名空间
Socket.io 通过自定义命名空间实现多路复用。(注意:不是 PHP 的命名空间)
-
可以通过
@SocketIONamespace("/xxx")
将控制器映射为 xxx 的命名空间, -
也可通过
<?php use Hyperf\SocketIOServer\Collector\SocketIORouter; use App\Controller\WebSocketController; SocketIORouter::addNamespace('/xxx' , WebSocketController::class);
在路由中添加。
开启 Session
安装并配置好 hyperf/session 组件及其对应中间件,再通过 SessionAspect
切入 SocketIO 来使用 Session 。
<?php // config/autoload/aspect.php return [ \Hyperf\SocketIOServer\Aspect\SessionAspect::class, ];
swoole 4.4.17 及以下版本只能读取 http 创建好的Cookie,4.4.18 及以上版本可以在WebSocket握手时创建Cookie
调整房间适配器
默认的房间功能通过 Redis 适配器实现,可以适应多进程乃至分布式场景。
- 可以替换为内存适配器,只适用于单 worker 场景。
<?php // config/autoload/dependencies.php return [ \Hyperf\SocketIOServer\Room\AdapterInterface::class => \Hyperf\SocketIOServer\Room\MemoryAdapter::class, ];
- 可以替换为空适配器,不需要房间功能时可以降低消耗。
<?php // config/autoload/dependencies.php return [ \Hyperf\SocketIOServer\Room\AdapterInterface::class => \Hyperf\SocketIOServer\Room\NullAdapter::class, ];
调整 SocketID (sid
)
默认 SocketID 使用 ServerID#FD
的格式,可以适应分布式场景。
- 可以替换为直接使用 Fd 。
<?php // config/autoload/dependencies.php return [ \Hyperf\SocketIOServer\SidProvider\SidProviderInterface::class => \Hyperf\SocketIOServer\SidProvider\LocalSidProvider::class, ];
- 也可以替换为 SessionID 。
<?php // config/autoload/dependencies.php return [ \Hyperf\SocketIOServer\SidProvider\SidProviderInterface::class => \Hyperf\SocketIOServer\SidProvider\SessionSidProvider::class, ];
其他事件分发方法
- 可以手动注册事件,不使用注解。
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\SocketIOServer\BaseNamespace; use Hyperf\SocketIOServer\SidProvider\SidProviderInterface; use Hyperf\SocketIOServer\Socket; use Hyperf\WebSocketServer\Sender; class WebSocketController extends BaseNamespace { public function __construct(Sender $sender, SidProviderInterface $sidProvider) { parent::__construct($sender,$sidProvider); $this->on('event', [$this, 'echo']); } public function echo(Socket $socket, $data) { $socket->emit('event', $data); } }
- 可以在控制器上添加
@Event()
注解,以方法名作为事件名来分发。此时应注意其他公有方法可能会和事件名冲突。
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\SocketIOServer\Annotation\SocketIONamespace; use Hyperf\SocketIOServer\Annotation\Event; use Hyperf\SocketIOServer\BaseNamespace; use Hyperf\SocketIOServer\Socket; /** * @SocketIONamespace("/") * @Event() */ class WebSocketController extends BaseNamespace { public function echo(Socket $socket, $data) { $socket->emit('event', $data); } }