fage1151/socketio

Socket.IO v4 compatible server based on Workerman

Maintainers

Package info

gitee.com/FEIGE/phpsocket.io

pkg:composer/fage1151/socketio

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

v0.1 2026-05-04 04:08 UTC

This package is not auto-updated.

Last update: 2026-05-04 16:55:39 UTC


README

Socket.IO 的 PHP 服务器实现,支持 WebSocket 和 Long-Polling 传输,完整兼容 Socket.IO 协议 v4。

基于 Workerman 实现的高性能、生产级别的 Socket.IO 服务器,专为 PHP 环境优化。

特性

  • 多传输协议支持:支持 WebSocket 和 HTTP Long-Polling(多进程模式下仅支持 WebSocket,且需要显式使用)
  • 二进制数据支持:支持二进制事件传输
  • 集群支持:通过 Channel 或 Redis 实现多进程集群通信
  • 房间管理:支持房间(Room)管理功能
  • 命名空间:支持多个命名空间,推荐使用 $io->of() 方法
  • 事件确认(ACK):支持双向 ACK 确认机制,强制使用 callback 回复
  • 三层中间件系统:支持全局、命名空间级别和 Socket 实例级别的中间件
  • 连接恢复机制:完整支持 Socket.IO v4 连接状态恢复(private id, offset tracking, state recovery)
  • 心跳检测:自动心跳保活机制
  • PSR-3 日志系统:支持 PSR-3 标准日志接口
  • PHP 8.1+ 优化实现:使用 PHP 8.1 最新特性,性能优化

系统要求

  • PHP >= 8.1
  • Workerman >= 4.0
  • psr/log >= 3.0
  • 可选依赖:
    • workerman/channel(使用 ClusterAdapter 时需要)
    • workerman/redis(使用 RedisAdapter 时需要)

安装

使用 Composer(推荐)

composer require fage1151/socketio

从 GitHub 克隆

# 克隆项目
git clone https://github.com/phpsocketio/socket.io.git

# 进入项目目录
cd socket.io

# 安装依赖
composer install

安装可选依赖

使用 ClusterAdapter 时:

ClusterAdapter 基于 Workerman Channel,默认不包含,需要安装:

composer require workerman/channel

使用 RedisAdapter 时:

composer require workerman/redis

项目结构

├── src/                          # 核心源码目录
│   ├── Adapter/                  # 适配器目录
│   │   ├── AdapterInterface.php  # 适配器接口(含跨进程方法)
│   │   ├── ClusterAdapter.php    # 基于Channel的集群适配器
│   │   └── RedisAdapter.php      # 基于Redis的集群适配器
│   ├── Protocol/                 # 协议相关
│   │   ├── PacketParser.php      # 数据包解析器
│   │   ├── PacketDispatcher.php  # 数据包分发器
│   │   └── EngineIOHandler.php   # Engine.IO协议处理器
│   ├── Transport/                # 传输层
│   │   ├── AbstractTransportHandler.php # 传输层基类
│   │   ├── WebSocketHandler.php  # WebSocket处理器
│   │   ├── PollingHandler.php    # 轮询处理器
│   │   └── ConnectionManager.php # 连接管理器
│   ├── Room/                     # 房间管理
│   │   └── RoomManager.php       # 房间管理器
│   ├── Event/                    # 事件系统
│   │   ├── EventHandler.php      # 事件处理器
│   │   └── AckManager.php        # ACK回调管理器
│   ├── Session/                  # 会话相关
│   │   ├── SessionStore.php      # 会话存储管理器
│   │   └── RecoveryManager.php   # 连接状态恢复管理器
│   ├── Enum/                     # 枚举类型
│   │   ├── EnginePacketType.php  # Engine.IO数据包类型枚举
│   │   ├── SocketPacketType.php  # Socket.IO数据包类型枚举
│   │   └── LogLevelPriority.php  # 日志级别优先级枚举
│   ├── Exceptions/               # 异常类
│   │   └── SocketIOException.php # Socket.IO统一异常类
│   ├── Support/                  # 支持类
│   │   ├── Logger.php            # PSR-3 兼容日志器
│   │   ├── ErrorHandler.php      # 错误处理器
│   │   ├── Set.php               # 集合数据结构
│   │   ├── ServerConfig.php      # 服务器配置类,管理配置
│   │   ├── ServerBuilder.php     # 服务器构建器,简化服务器创建
│   │   └── ServerManager.php     # 服务器管理器
│   ├── SocketIOServer.php        # Socket.IO服务器主类
│   ├── Socket.php                # Socket类
│   ├── SocketEventEmitter.php    # Socket事件发射器Trait
│   ├── SocketNamespace.php       # 命名空间处理类
│   ├── Session.php               # 会话管理
│   └── Broadcaster.php           # 统一广播器
├── examples/                     # 示例目录
│   └── server.php                # 完整服务器示例
├── docs/                         # 文档目录
│   ├── API.md                    # API参考文档
│   └── USAGE.md                  # 详细使用文档
├── tests/                        # 测试目录
├── README.md                     # 项目说明文档(中文)
├── README.en.md                  # 项目说明文档(英文)
├── composer.json                 # Composer配置
├── phpstan.neon                  # PHPStan配置
├── phpcs.xml                     # PHPCS配置
└── LICENSE                       # 许可证文件

核心文件说明

核心类(根目录)

  • src/SocketIOServer.php:Socket.IO 服务器主类,负责处理连接和事件分发
  • src/SocketNamespace.php:命名空间处理类,通过 $io->of() 访问
  • src/Session.php:会话管理,管理客户端会话状态和连接恢复
  • src/Socket.php:Socket 类,封装客户端连接接口
  • src/SocketEventEmitter.php:Socket事件发射器Trait,封装Socket事件处理功能
  • src/Broadcaster.php:统一广播器,负责消息广播

协议相关(Protocol/)

  • src/Protocol/PacketParser.php:数据包解析器,解析和构建 Socket.IO 数据包(使用静态映射性能优化)
  • src/Protocol/PacketDispatcher.php:数据包分发器,处理Socket.IO包的分发
  • src/Protocol/EngineIOHandler.php:Engine.IO 协议处理器,处理底层传输协议(使用回调解耦)

传输层(Transport/)

  • src/Transport/AbstractTransportHandler.php:传输层基类,包含通用的 IP 提取和握手数据构建
  • src/Transport/WebSocketHandler.php:WebSocket 处理器,处理 HTTP 轮询和 WebSocket 握手
  • src/Transport/PollingHandler.php:轮询处理器
  • src/Transport/ConnectionManager.php:连接管理器

房间管理(Room/)

  • src/Room/RoomManager.php:房间管理器,处理房间相关操作

事件系统(Event/)

  • src/Event/EventHandler.php:事件处理器,负责处理各种 Socket.IO 事件
  • src/Event/AckManager.php:ACK回调管理器,管理ack回调(统一管理所有ACK)

适配器(Adapter/)

  • src/Adapter/AdapterInterface.php:适配器接口,定义跨进程通信标准
  • src/Adapter/RedisAdapter.php:Redis 适配器,支持跨进程房间和会话管理
  • src/Adapter/ClusterAdapter.php:Channel 适配器,支持跨进程房间和会话管理

AdapterInterface 跨进程方法

方法说明
allSockets(array $rooms = [])获取所有连接的 Socket ID 集合(跨进程)
fetchSockets(array $rooms = [])获取所有 Socket 实例信息(跨进程)
socketsJoin(string\|array $rooms, array $targetSockets = [])让指定 Socket 加入房间(跨进程)
socketsLeave(string\|array $rooms, array $targetSockets = [])让指定 Socket 离开房间(跨进程)
disconnectSockets(bool $close = false, array $targetSockets = [])断开指定 Socket 连接(跨进程)
serverSideEmit(string $eventName, array $args = [], ?callable $ack = null)向集群中其他服务器发送消息

枚举类型(Enum/)

  • src/Enum/EnginePacketType.php:Engine.IO 数据包类型枚举
  • src/Enum/SocketPacketType.php:Socket.IO 数据包类型枚举
  • src/Enum/LogLevelPriority.php:日志级别优先级枚举

异常类(Exceptions/)

  • src/Exceptions/SocketIOException.php:Socket.IO统一异常类(提供静态方法创建不同类型异常)

会话相关(Session/)

  • src/Session/SessionStore.php:会话存储管理器,专门管理会话存储和缓存
  • src/Session/RecoveryManager.php:连接状态恢复管理器,处理重连状态恢复

支持类(Support/)

  • src/Support/Logger.php:PSR-3 兼容日志器
  • src/Support/ErrorHandler.php:错误处理器
  • src/Support/Set.php:集合数据结构(使用关联数组O(1)查找性能优化)
  • src/Support/ServerConfig.php:服务器配置类,单一职责管理配置
  • src/Support/ServerBuilder.php:服务器构建器,流畅 API 简化服务器创建
  • src/Support/ServerManager.php:服务器管理器,管理生命周期和适配器

架构优化说明

重构目标

项目经过多次优化重构,实现了:

  • 高内聚:每个类职责清晰单一
  • 低耦合:组件间依赖关系简化
  • 低冗余:消除了重复代码
  • 高性能:多处性能优化
  • 易维护:代码结构清晰,PHPStan 0 错误

主要重构工作

  1. 从SocketIOServer提取PacketDispatcher:专门处理数据包分发
  2. 从EventHandler提取AckManager:统一管理所有ACK回调
  3. 合并SocketConn到Socket:消除冗余包装类
  4. 从Session提取SessionStore和RecoveryManager:分离静态存储和恢复逻辑独立
  5. 从Socket提取SocketEventEmitter Trait:降低Socket类复杂度
  6. 移除双重分派:EventHandler不再需要再进行双重路由,直接使用PacketDispatcher
  7. Set性能优化:从O(n)查找改为O(1)查找
  8. PacketParser静态映射:性能优化
  9. 异常类合并:3个异常类合并为1个,使用静态工厂方法
  10. Broadcaster链式调用优化:使用clone替代直接调用,减少构造器开销
  11. EngineIOHandler解耦:使用回调替代直接依赖EventHandler和RoomManager
  12. fetchSockets简化:使用更简洁if替代复杂闭包
  13. initializeMaps方法优化:显式初始化静态映射
  14. 移除AckManager中ReflectionFunction调用:减少不必要的性能开销
  15. Adapter跨进程方法补充:新增allSockets、fetchSockets、socketsJoin、socketsLeave、disconnectSockets方法

性能提升

  • Set类查找性能从O(n)提升至O(1)
  • PacketParser类型查找不再遍历枚举改为静态映射
  • 消除了多处冗余对象构造函数减少开销
  • 移除了多处重复路由,简化ACK
  • ACK回调管理统一,减少Session与AckManager间的重复
  • Adapter支持完整的跨进程操作

快速开始

基本用法

use Workerman\Worker;
use PhpSocketIO\SocketIOServer;
use Psr\Log\LogLevel;

// 创建 Socket.IO 服务器实例
$io = new SocketIOServer('0.0.0.0:8088', [
    'pingInterval' => 25000,  // 心跳间隔(毫秒)
    'pingTimeout'  => 20000,  // 心跳超时(毫秒)
    'maxPayload'   => 10485760, // 最大负载(字节)
    'workerCount'  => 1,       // worker 数量,默认为 1
    'logLevel'     => LogLevel::INFO, // 日志级别
]);

// 使用 $io->of() 注册命名空间的连接事件处理
$io->of('/chat')->on('connection', function ($socket) use ($io) {
    // 检查是否是重连恢复的连接
    if ($socket->recovered) {
        echo "连接已恢复,继续使用之前的数据!\n";
        // $socket->data 和房间信息已自动恢复
        // 可以重发可能丢失的消息
    }
    
    // 发送欢迎消息
    $socket->emit('welcome', 'Welcome to Socket.IO server!');
    
    // 设置 socket 的自定义数据(断连时会保存,重连时会恢复)
    $socket->data['userId'] = 'user_' . time();
    $socket->data['name'] = 'Guest';
    
    // 加入房间(断连时会保存,重连时会自动恢复)
    $socket->join('welcome');
    
    // 聊天消息处理
    $socket->on('chat message', function ($msg) use ($socket) {
        $socket->broadcast->emit('chat message', $msg);
    });
    
    // ACK 消息处理 - 强制使用 callback,不要使用 return
    $socket->on('ack', function ($msg, $callback = null) use ($socket) {
        if (is_callable($callback)) {
            $callback(['status' => 'ok', 'data' => $msg]);
        }
    });
    
    // 断开连接处理
    $socket->on('disconnect', function () use ($socket) {
        // 清理逻辑(注意:断开时会自动保存状态用于恢复)
    });
});

// 启动 Workerman
Worker::runAll();

使用 ServerBuilder 流畅 API

use Workerman\Worker;
use PhpSocketIO\Support\ServerBuilder;
use Psr\Log\LogLevel;

// 使用 ServerBuilder 流畅 API 创建服务器
$io = ServerBuilder::create()
    ->listen('0.0.0.0:8088')
    ->pingInterval(25000)
    ->pingTimeout(20000)
    ->workerCount(1)
    ->logLevel(LogLevel::INFO)
    ->cors('*')
    ->build();

// 后续操作和普通方式一样
$io->of('/chat')->on('connection', function ($socket) {
    $socket->emit('welcome', 'Welcome!');
});

Worker::runAll();

使用日志

use Psr\Log\LogLevel;

// 1. 使用内置日志器(默认)
$io = new SocketIOServer('0.0.0.0:8088', [
    'logLevel' => LogLevel::DEBUG
]);

// 2. 设置自定义日志处理器
$io->getLogger()->setHandler(function ($level, $message, $context) {
    // 这里可以写入文件、数据库、或者其他日志服务
    file_put_contents('/path/to/logs/socketio.log',
        "[{$level}] {$message}\n", FILE_APPEND
    );
});

// 3. 使用第三方 PSR-3 日志库,如 Monolog
$logger = new \Monolog\Logger('socketio');
$logger->pushHandler(new \Monolog\Handler\StreamHandler('/path/to/logs/socketio.log'));
$io->setLogger($logger);

使用中间件

// 1. 全局中间件 - 作用于所有命名空间和事件
$io->use(function ($socket, $packet, $next) {
    $sid = $socket['id'] ?? 'unknown';
    echo "[Global Middleware] SID: {$sid}\n";
    $next();
});

// 2. 命名空间级中间件 - 只作用于 /chat 命名空间
$io->of('/chat')->use(function ($socket, $packet, $next) {
    echo "[Namespace Middleware] /chat\n";
    $next();
});

// 3. Socket 实例级中间件 - 只作用于当前连接
$io->of('/chat')->on('connection', function ($socket) {
    $socket->use(function ($packet, $next) use ($socket) {
        echo "[Socket Middleware] Socket {$socket->id}\n";
        $next();
    });
});

多 worker 配置示例

当需要使用多个 worker 进程时,必须通过 setAdapter 方法设置 adapter:

使用 ClusterAdapter(基于 Workerman Channel)

注意:使用 ClusterAdapter 需要先安装 workerman/channel:

composer require workerman/channel
use Workerman\Worker;
use PhpSocketIO\SocketIOServer;
use PhpSocketIO\Adapter\ClusterAdapter;

// 创建多 worker 服务器实例(4个 worker)
$io = new SocketIOServer('0.0.0.0:8088', [
    'pingInterval' => 25000,
    'pingTimeout'  => 20000,
    'workerCount'  => 4,  // 设置 4 个 worker
]);

// 创建并设置集群适配器
$adapter = new ClusterAdapter([
    'channel_ip' => '127.0.0.1',
    'channel_port' => 2206,
    'prefix' => 'socketio_',
    'heartbeat' => 25
]);
$io->setAdapter($adapter);

// 事件处理代码...
$io->of('/chat')->on('connection', function ($socket) {
    // 处理连接...
});

Worker::runAll();

使用 RedisAdapter(基于 Redis)

注意:使用 RedisAdapter 需要先安装 workerman/redis:

composer require workerman/redis
use Workerman\Worker;
use PhpSocketIO\SocketIOServer;
use PhpSocketIO\Adapter\RedisAdapter;

// 创建多 worker 服务器实例(4个 worker)
$io = new SocketIOServer('0.0.0.0:8088', [
    'pingInterval' => 25000,
    'pingTimeout'  => 20000,
    'workerCount'  => 4,  // 设置 4 个 worker
]);

// 创建并设置 Redis 适配器
$adapter = new RedisAdapter([
    'host' => '127.0.0.1',
    'port' => 6379,
    'auth' => null,  // Redis 认证密码,无密码时为 null
    'db' => 0,       // Redis 数据库编号
    'prefix' => 'socketio_',
    'heartbeat' => 25
]);
$io->setAdapter($adapter);

// 事件处理代码...
$io->of('/chat')->on('connection', function ($socket) {
    // 处理连接...
});

Worker::runAll();

房间操作

$io->of('/chat')->on('connection', function ($socket) use ($io) {
    // 加入房间
    $socket->join('room1');
    
    // 离开房间
    $socket->leave('room1');
    
    // 只向指定房间发送
    $io->of('/chat')->to('room1')->emit('some event', 'message');
    
    // 向多个房间发送
    $io->of('/chat')->to('room1')->to('room2')->emit('some event', 'message');
    
    // 广播(排除当前 socket)
    $socket->broadcast->emit('some event', 'message');
    
    // 在指定房间内广播
    $socket->to('room1')->emit('some event', 'message');
    
    // 排除特定房间
    $socket->except('room2')->emit('some event', 'message');
});

事件确认(ACK)

重要:ACK 回复必须使用 callback,不要使用 return!

$io->of('/chat')->on('connection', function ($socket) {
    $socket->on('reqAck', function ($data, $callback = null) {
        // 处理数据
        $result = ['status' => 'ok', 'data' => $data];
        
        // 调用 callback 发送确认
        if (is_callable($callback)) {
            $callback($result);
        }
    });
    
    // 服务器发送带 ACK 的消息给客户端
    $socket->on('ping', function () use ($socket) {
        $socket->emitWithAck('ackResponse', 'Hello', function ($clientData) {
            // 处理客户端回复
        });
    });
});

连接恢复机制

本项目完整实现了 Socket.IO v4 连接状态恢复机制,当客户端网络不稳定导致断连后,可以恢复之前的会话状态。

特性

  • 自动保存状态:断开连接时自动保存房间信息、自定义数据和已发送消息
  • 状态恢复:重连时自动恢复房间和自定义数据
  • 丢失消息重发:通过 offset 跟踪,自动重发可能丢失的消息
  • 简便使用:通过 $socket->recovered 属性检查连接是否成功恢复

使用示例

$io->of('/chat')->on('connection', function ($socket) use ($io) {
    // 检查连接是否已恢复
    if ($socket->recovered) {
        echo "用户已恢复连接!\n";
        // $socket->data 和房间信息已自动恢复
        // 可以检查 $socket->data 中是否有需要续传的数据
    } else {
        echo "新用户连接!\n";
        // 新连接,初始化数据
        $socket->data['username'] = 'Guest_' . mt_rand();
    }
    
    // 设置自定义数据(断连后会保存,重连后会恢复)
    $socket->data['lastActive'] = time();
    
    // 加入房间(断连后会保存,重连后会自动恢复)
    $socket->join('chat_room');
    
    // 发送消息(offset 会自动跟踪)
    $socket->emit('system_message', '欢迎来到聊天室!');
});

客户端配置

客户端需要启用重连机制(Socket.IO 客户端默认已启用):

const io = require('socket.io-client');

// 连接服务器(默认重连已启用)
const socket = io('http://localhost:8088/chat', {
    // 可选:自定义重连参数
    reconnection: true,
    reconnectionDelay: 100,
    reconnectionDelayMax: 500,
    reconnectionAttempts: 10,
});

工作原理

  1. 连接建立:服务器为每个连接生成唯一的 pid(private id)
  2. 消息跟踪:每个发送的事件都带有 offset 标记
  3. 断连保存:连接断开时,服务器保存:
    • 当前连接的所有房间
    • $socket->data 中的自定义数据
    • 最近发送的事件列表(带 offset)
  4. 重连恢复
    • 客户端重连时发送之前的 pid 和最新的 offset
    • 服务器验证 pid 是否有效且未超时
    • 自动恢复房间信息和自定义数据
    • 重发 offset 之后可能丢失的消息
    • 设置 $socket->recovered = true
  5. 过期清理:保存的状态 120 秒后自动过期

配置选项

连接恢复机制内置在服务器中,无需额外配置。以下是默认参数:

  • 恢复超时:120 秒(超过此时间的状态无法恢复)
  • 最大保存消息数:1000 条(最多保存的事件数量)

配置选项

选项类型默认值描述
pingIntervalint25000心跳间隔(毫秒)
pingTimeoutint20000心跳超时(毫秒)
maxPayloadint10485760最大负载大小(字节)
workerCountint1Worker 进程数量
logLevelstringLogLevel::INFO日志级别(PSR-3)
sslarray[]SSL 配置(用于 HTTPS/WSS)
corsarray/stringnullCORS 跨域配置

CORS 配置

支持以下几种配置方式:

// 方式1:简单配置,仅指定允许的源
$io = new SocketIOServer('0.0.0.0:8088', [
    'cors' => 'https://example.com'
]);

// 方式2:完整配置
$io = new SocketIOServer('0.0.0.0:8088', [
    'cors' => [
        'origin' => 'https://example.com',
        'methods' => ['GET', 'POST', 'OPTIONS'],
        'allowedHeaders' => ['my-custom-header', 'Content-Type'],
        'credentials' => true
    ]
]);

// 方式3:允许多个源(需要动态处理)
$io = new SocketIOServer('0.0.0.0:8088', [
    'cors' => [
        'origin' => ['https://example.com', 'https://app.example.com'],
        'methods' => ['GET', 'POST', 'OPTIONS'],
        'allowedHeaders' => ['Content-Type', 'Authorization'],
        'credentials' => true
    ]
]);

CORS 配置选项说明

选项类型默认值描述
originstring/array*允许的源,可以是字符串或数组
methodsarray['GET', 'POST', 'OPTIONS']允许的 HTTP 方法
allowedHeadersarray['Content-Type', 'Authorization']允许的请求头
credentialsboolfalse是否允许携带凭证(Cookies)

启动服务器

使用提供的 server.php 启动服务器:

# 启动服务器(前台运行)
php server.php

# 以守护进程方式启动(后台运行)
php server.php -d

# 查看服务器状态
php server.php status

# 停止服务器
php server.php stop

更多信息

详细使用说明请参考 docs/USAGE.md 文件,包括:

  • 完整的三层中间件系统文档
  • 命名空间正确用法
  • ACK 机制详细说明
  • API 参考文档
  • 故障排除指南
  • 性能优化建议
  • 安全注意事项

版本历史

  • v1.6.0:完整架构优化重构,实现高内聚低耦合,多项性能优化,PHPStan 0错误

    • 新增SessionStore专门管理会话存储
    • 新增SocketEventEmitter Trait,降低Socket类复杂度
    • 统一ACK回调管理
    • 优化Set类查找性能O(n) → O(1)
    • PacketParser使用静态映射替代枚举遍历
    • Broadcaster链式调用优化使用clone
    • 异常类合并为1个统一类
    • EngineIOHandler使用回调解耦
    • 消除双重分派和冗余代码
    • Adapter新增跨进程方法:allSockets、fetchSockets、socketsJoin、socketsLeave、disconnectSockets
    • 大量性能优化点
  • v1.5.0:完整实现 Socket.IO v4 连接恢复机制,添加 $socket->recovered 属性,支持状态恢复、房间恢复和丢失消息重发

  • v1.4.0:PHP 8.1+优化,完整的三层中间件系统,修复ACK机制,统一$io->of()用法
  • v1.3.0:优化性能和稳定性,添加PSR-3日志
  • v1.2.0:添加集群模式支持
  • v1.1.0:添加二进制数据传输支持
  • v1.0.0:初始版本,支持Socket.IO v4协议

贡献指南

欢迎提交 Issue 和 Pull Request 来改进这个项目。在提交代码前,请确保:

  1. 代码符合项目的代码风格(遵循 PSR 规范)
  2. 添加了适当的测试
  3. 文档已经更新(README.md, USAGE.md 等)
  4. 所有 PHP 语法检查通过

许可证

本项目采用 MulanPSL-2.0 许可证,详见 LICENSE 文件。