{"id":18345850,"url":"https://github.com/hyperf/socketio-server","last_synced_at":"2025-04-06T08:32:26.608Z","repository":{"id":38134057,"uuid":"261626857","full_name":"hyperf/socketio-server","owner":"hyperf","description":"[READ ONLY]","archived":false,"fork":false,"pushed_at":"2024-05-23T03:58:20.000Z","size":152,"stargazers_count":20,"open_issues_count":10,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-05-23T04:59:10.031Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hyperf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"open_collective":"hyperf","custom":"https://hyperf.wiki/#/zh-cn/donate"}},"created_at":"2020-05-06T01:55:42.000Z","updated_at":"2024-06-20T04:00:20.714Z","dependencies_parsed_at":"2023-02-08T08:16:13.522Z","dependency_job_id":"1e822c4b-6635-4cd1-981c-ce6e5f795ecd","html_url":"https://github.com/hyperf/socketio-server","commit_stats":null,"previous_names":[],"tags_count":69,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperf%2Fsocketio-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperf%2Fsocketio-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperf%2Fsocketio-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperf%2Fsocketio-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyperf","download_url":"https://codeload.github.com/hyperf/socketio-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223245061,"owners_count":17112572,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T21:09:45.537Z","updated_at":"2024-11-05T21:09:46.258Z","avatar_url":"https://github.com/hyperf.png","language":"PHP","readme":"Socket.io是一款非常流行的应用层实时通讯协议和框架，可以轻松实现应答、分组、广播。hyperf/socketio-server支持了Socket.io的WebSocket传输协议。\n\n## 安装\n\n```bash\ncomposer require hyperf/socketio-server\n```\n\nhyperf/socketio-server 是基于WebSocket实现的，请确保服务端已经添加了WebSocket服务配置。\n\n```php\n        [\n            'name' =\u003e 'socket-io',\n            'type' =\u003e Server::SERVER_WEBSOCKET,\n            'host' =\u003e '0.0.0.0',\n            'port' =\u003e 9502,\n            'sock_type' =\u003e SWOOLE_SOCK_TCP,\n            'callbacks' =\u003e [\n                SwooleEvent::ON_HAND_SHAKE =\u003e [Hyperf\\WebSocketServer\\Server::class, 'onHandShake'],\n                SwooleEvent::ON_MESSAGE =\u003e [Hyperf\\WebSocketServer\\Server::class, 'onMessage'],\n                SwooleEvent::ON_CLOSE =\u003e [Hyperf\\WebSocketServer\\Server::class, 'onClose'],\n            ],\n        ],\n```\n\n\n## 快速开始\n\n### 服务端\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\SocketIOServer\\Annotation\\Event;\nuse Hyperf\\SocketIOServer\\Annotation\\SocketIONamespace;\nuse Hyperf\\SocketIOServer\\BaseNamespace;\nuse Hyperf\\SocketIOServer\\Socket;\nuse Hyperf\\Codec\\Json;\n\n/**\n * @SocketIONamespace(\"/\")\n */\nclass WebSocketController extends BaseNamespace\n{\n    /**\n     * @Event(\"event\")\n     * @param string $data\n     */\n    public function onEvent(Socket $socket, $data)\n    {\n        // 应答\n        return 'Event Received: ' . $data;\n    }\n\n    /**\n     * @Event(\"join-room\")\n     * @param string $data\n     */\n    public function onJoinRoom(Socket $socket, $data)\n    {\n        // 将当前用户加入房间\n        $socket-\u003ejoin($data);\n        // 向房间内其他用户推送（不含当前用户）\n        $socket-\u003eto($data)-\u003eemit('event', $socket-\u003egetSid() . \"has joined {$data}\");\n        // 向房间内所有人广播（含当前用户）\n        $this-\u003eemit('event', 'There are ' . count($socket-\u003egetAdapter()-\u003eclients($data)) . \" players in {$data}\");\n    }\n\n    /**\n     * @Event(\"say\")\n     * @param string $data\n     */\n    public function onSay(Socket $socket, $data)\n    {\n        $data = Json::decode($data);\n        $socket-\u003eto($data['room'])-\u003eemit('event', $socket-\u003egetSid() . \" say: {$data['message']}\");\n    }\n}\n\n```\n\n\u003e 每个 socket 会自动加入以自己 `sid` 命名的房间（`$socket-\u003egetSid()`），发送私聊信息就推送到对应 `sid` 即可。\n\n\u003e 框架会触发 `connect` 和 `disconnect` 两个事件。\n\n### 客户端\n\n由于服务端只实现了WebSocket通讯，所以客户端要加上 `{transports:[\"websocket\"]}` 。\n\n```html\n\u003cscript src=\"https://cdn.bootcdn.net/ajax/libs/socket.io/2.3.0/socket.io.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n    var socket = io('ws://127.0.0.1:9502', { transports: [\"websocket\"] });\n    socket.on('connect', data =\u003e {\n        socket.emit('event', 'hello, hyperf', console.log);\n        socket.emit('join-room', 'room1', console.log);\n        setInterval(function () {\n            socket.emit('say', '{\"room\":\"room1\", \"message\":\"Hello Hyperf.\"}');\n        }, 1000);\n    });\n    socket.on('event', console.log);\n\u003c/script\u003e\n```\n\n## API 清单\n\n```php\n\u003c?php\nfunction onConnect(\\Hyperf\\SocketIOServer\\Socket $socket){\n\n  // sending to the client\n  $socket-\u003eemit('hello', 'can you hear me?', 1, 2, 'abc');\n\n  // sending to all clients except sender\n  $socket-\u003ebroadcast-\u003eemit('broadcast', 'hello friends!');\n\n  // sending to all clients in 'game' room except sender\n  $socket-\u003eto('game')-\u003eemit('nice game', \"let's play a game\");\n\n  // sending to all clients in 'game1' and/or in 'game2' room, except sender\n  $socket-\u003eto('game1')-\u003eto('game2')-\u003eemit('nice game', \"let's play a game (too)\");\n\n  // WARNING: `$socket-\u003eto($socket-\u003egetSid())-\u003eemit()` will NOT work, as it will send to everyone in the room\n  // named `$socket-\u003egetSid()` but the sender. Please use the classic `$socket-\u003eemit()` instead.\n\n  // sending with acknowledgement\n  $reply = $socket-\u003eemit('question', 'do you think so?')-\u003ereply();\n\n  // sending without compression\n  $socket-\u003ecompress(false)-\u003eemit('uncompressed', \"that's rough\");\n\n  $io = \\Hyperf\\Context\\ApplicationContext::getContainer()-\u003eget(\\Hyperf\\SocketIOServer\\SocketIO::class);\n\n  // sending to all clients in 'game' room, including sender\n  $io-\u003ein('game')-\u003eemit('big-announcement', 'the game will start soon');\n\n  // sending to all clients in namespace 'myNamespace', including sender\n  $io-\u003eof('/myNamespace')-\u003eemit('bigger-announcement', 'the tournament will start soon');\n\n  // sending to a specific room in a specific namespace, including sender\n  $io-\u003eof('/myNamespace')-\u003eto('room')-\u003eemit('event', 'message');\n\n  // sending to individual socketid (private message)\n  $io-\u003eto('socketId')-\u003eemit('hey', 'I just met you');\n\n  // sending to all clients on this node (when using multiple nodes)\n  $io-\u003elocal-\u003eemit('hi', 'my lovely babies');\n\n  // sending to all connected clients\n  $io-\u003eemit('an event sent to all connected clients');\n\n};\n```\n\n## 进阶教程\n\n### 设置 Socket.io 命名空间\n\nSocket.io 通过自定义命名空间实现多路复用。（注意：不是 PHP 的命名空间）\n\n1. 可以通过 `@SocketIONamespace(\"/xxx\")` 将控制器映射为 xxx 的命名空间，\n\n2. 也可通过\n\n```php\n\u003c?php\nuse Hyperf\\SocketIOServer\\Collector\\SocketIORouter;\nuse App\\Controller\\WebSocketController;\nSocketIORouter::addNamespace('/xxx' , WebSocketController::class);\n```\n\n在路由中添加。\n\n### 开启 Session \n\n安装并配置好 hyperf/session 组件及其对应中间件，再通过 `SessionAspect` 切入 SocketIO 来使用 Session 。\n\n```php\n\u003c?php\n// config/autoload/aspect.php\nreturn [\n    \\Hyperf\\SocketIOServer\\Aspect\\SessionAspect::class,\n];\n```\n\n\u003e swoole 4.4.17 及以下版本只能读取 http 创建好的Cookie，4.4.18 及以上版本可以在WebSocket握手时创建Cookie\n\n### 调整房间适配器\n\n默认的房间功能通过 Redis 适配器实现，可以适应多进程乃至分布式场景。\n\n1. 可以替换为内存适配器，只适用于单 worker 场景。\n```php\n\u003c?php\n// config/autoload/dependencies.php\nreturn [\n    \\Hyperf\\SocketIOServer\\Room\\AdapterInterface::class =\u003e \\Hyperf\\SocketIOServer\\Room\\MemoryAdapter::class,\n];\n```\n\n2. 可以替换为空适配器，不需要房间功能时可以降低消耗。\n```php\n\u003c?php\n// config/autoload/dependencies.php\nreturn [\n    \\Hyperf\\SocketIOServer\\Room\\AdapterInterface::class =\u003e \\Hyperf\\SocketIOServer\\Room\\NullAdapter::class,\n];\n```\n\n### 调整 SocketID (`sid`)\n\n默认 SocketID 使用 `ServerID#FD` 的格式，可以适应分布式场景。\n\n1. 可以替换为直接使用 Fd 。\n\n```php\n\u003c?php\n// config/autoload/dependencies.php\nreturn [\n    \\Hyperf\\SocketIOServer\\SidProvider\\SidProviderInterface::class =\u003e \\Hyperf\\SocketIOServer\\SidProvider\\LocalSidProvider::class,\n];\n```\n\n2. 也可以替换为 SessionID 。\n\n```php\n\u003c?php\n// config/autoload/dependencies.php\nreturn [\n    \\Hyperf\\SocketIOServer\\SidProvider\\SidProviderInterface::class =\u003e \\Hyperf\\SocketIOServer\\SidProvider\\SessionSidProvider::class,\n];\n```\n\n### 其他事件分发方法\n\n1. 可以手动注册事件，不使用注解。\n\n```php\n\u003c?php\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\SocketIOServer\\BaseNamespace;\nuse Hyperf\\SocketIOServer\\SidProvider\\SidProviderInterface;\nuse Hyperf\\SocketIOServer\\Socket;\nuse Hyperf\\WebSocketServer\\Sender;\n\nclass WebSocketController extends BaseNamespace\n{\n    public function __construct(Sender $sender, SidProviderInterface $sidProvider) {\n        parent::__construct($sender,$sidProvider);\n        $this-\u003eon('event', [$this, 'echo']);\n    }\n\n    public function echo(Socket $socket, $data)\n    {\n        $socket-\u003eemit('event', $data);\n    }\n}\n```\n\n2. 可以在控制器上添加 `@Event()` 注解，以方法名作为事件名来分发。此时应注意其他公有方法可能会和事件名冲突。\n\n```php\n\u003c?php\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\SocketIOServer\\Annotation\\SocketIONamespace;\nuse Hyperf\\SocketIOServer\\Annotation\\Event;\nuse Hyperf\\SocketIOServer\\BaseNamespace;\nuse Hyperf\\SocketIOServer\\Socket;\n\n/**\n * @SocketIONamespace(\"/\")\n * @Event()\n */\nclass WebSocketController extends BaseNamespace\n{\n    public function echo(Socket $socket, $data)\n    {\n        $socket-\u003eemit('event', $data);\n    }\n}\n```\n","funding_links":["https://opencollective.com/hyperf","https://hyperf.wiki/#/zh-cn/donate"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperf%2Fsocketio-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyperf%2Fsocketio-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperf%2Fsocketio-server/lists"}