跳转至

WebSocket API

本文引用的文件
- README.md - websocket_ingress_runtime.v - dispatch_session.v - hub_runtime.v - runtime.v - types.v - WEBSOCKET_PHASE2_IMPLEMENTATION_PLAN.md - WEBSOCKET_EVENT_BUS_PLAN.md - websocket_echo.toml - websocket_echo_app.js

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件为 vhttpd 的 WebSocket API 完整文档,覆盖连接建立流程、握手协议、消息格式定义、事件类型与实时交互模式;说明连接管理、会话亲和性、房间系统、消息广播等功能;包含连接生命周期管理、重连机制、错误处理与断线恢复策略;提供完整的消息格式示例、事件订阅模式、客户端实现指南和性能优化建议;并记录 WebSocket 代理、负载均衡和高可用配置要点。

vhttpd 在传输层支持 HTTP/WebSocket/流式响应,在运行时层提供上游流式执行、外部 worker 编排、内嵌宿主执行、MCP 等能力。WebSocket 同时支持两种模式: - Phase 1(长连接桥接):worker 持有长连接,vhttpd 作为透传桥。 - Phase 2(事件分发):vhttpd 持有连接,worker 以短任务方式处理 open/message/close 事件,返回命令列表由 vhttpd 执行。

章节来源 - README.md:45-83 - README.md:191-208

项目结构

WebSocket 相关代码主要分布在以下模块: - 接入与升级:HTTP 到 WebSocket 的升级、握手、路由选择(Phase 1/Phase 2) - 分发会话:Phase 2 的连接生命周期与消息派发 - Hub 状态与房间:连接注册、房间成员、元数据、广播、快照 - 类型与帧:统一的 Worker 帧结构与命令语义 - 计划与设计文档:Phase 2 的事件分发模型、事件总线扩展方向

graph TB
Client["客户端浏览器"] --> Ingress["HTTP 接入<br/>websocket_ingress_runtime.v"]
Ingress --> |Phase 1| Bridge["长连接桥接<br/>handle_worker_websocket_session"]
Ingress --> |Phase 2| Dispatch["事件分发会话<br/>ws.handle_dispatch_session"]
Dispatch --> Hub["Hub 状态与房间<br/>ws.hub_runtime / ws.runtime"]
Bridge --> Worker["php-worker 长连接"]
Dispatch --> Worker
Hub --> Admin["管理快照/房间/连接"]

图表来源 - websocket_ingress_runtime.v:279-339 - websocket_ingress_runtime.v:413-482 - dispatch_session.v:11-35 - hub_runtime.v:174-334

章节来源 - websocket_ingress_runtime.v:279-339 - dispatch_session.v:11-35 - hub_runtime.v:174-334

核心组件

  • 接入与升级
  • 检测 Upgrade 请求、解析 key、选择 Phase 1 或 Phase 2 路径
  • Phase 1:与 php-worker 建立 Unix Socket 长连接,双向转发
  • Phase 2:完成握手后直接由 vhttpd 持有连接,按事件派发至 worker
  • 分发会话(Phase 2)
  • 维护连接生命周期状态机(opening/open/closing/closed)
  • 构建 open/message/close 事件帧,调用 RuntimeContext 派发
  • 执行 worker 返回的命令(send/send_to/join/leave/broadcast/close/set_meta/clear_meta)
  • Hub 状态与房间
  • 连接注册/注销、房间成员管理、连接元数据
  • 发送队列与延迟写入、批量广播、存在性快照
  • 类型与帧
  • 统一 Worker 帧结构,包含 mode/event/id/opcode/data/rooms/metadata/presence 等字段
  • 命令失败回退与关闭策略

章节来源 - websocket_ingress_runtime.v:16-30 - dispatch_session.v:11-35 - types.v:11-120 - runtime.v:24-47 - hub_runtime.v:369-436

架构总览

下图展示从客户端到 worker 的两条路径以及 Hub 的房间与广播能力。

sequenceDiagram
participant C as "客户端"
participant I as "接入层<br/>websocket_ingress_runtime.v"
participant D as "分发会话<br/>ws.dispatch_session"
participant H as "Hub 状态<br/>ws.hub_runtime/ws.runtime"
participant W as "php-worker"
Note over I : 检测 Upgrade 与 key
I->>I : is_websocket_upgrade()
alt Phase 2 启用
I->>D : handle_dispatch_session(...)
D->>H : register_conn(..., lifecycle)
D->>W : dispatch_event(open_frame)
W-->>D : commands[]
D->>H : command_result(commands)
D-->>C : 握手成功/执行 open 命令
else Phase 1 桥接
I->>W : 建立 unix socket 长连接
I->>W : write_websocket_frame(open)
W-->>I : accept/close/error/done
I-->>C : 101 Switching Protocols
loop 消息往返
C-->>I : text/binary frame
I->>W : message/close 帧
W-->>I : send/close/done 帧
I-->>C : 转发结果
end
end

图表来源 - websocket_ingress_runtime.v:279-339 - websocket_ingress_runtime.v:413-482 - dispatch_session.v:11-35 - hub_runtime.v:174-334

详细组件分析

连接建立与握手协议

  • 握手入口
  • 检查 GET 方法、Upgrade=websocket、Connection 包含 upgrade、Sec-WebSocket-Key 非空
  • 若匹配则进入 WebSocket 处理分支
  • Phase 1(长连接桥接)
  • 通过 engines.open_websocket_session 获取 worker 连接
  • 向 worker 发送 open 帧,等待 accept/close/error/done
  • 成功后 101 切换协议,进入消息循环
  • Phase 2(事件分发)
  • 完成 net.websocket 握手后,注册连接并派发 open 事件
  • worker 返回命令列表,vhttpd 执行(如 set_meta/join/send)
  • 握手完成后进入消息派发循环
flowchart TD
Start(["HTTP 请求"]) --> Check["检测 Upgrade 与 Key"]
Check --> |不满足| Reject["返回 426 Upgrade Required"]
Check --> |满足| Mode{"是否启用 Phase 2?"}
Mode --> |是| P2["handle_dispatch_session<br/>注册连接 -> 派发 open -> 执行命令"]
Mode --> |否| P1["open_websocket_session -> 发送 open 帧 -> 等待 accept/done"]
P1 --> Handshake["101 Switching Protocols"]
P2 --> Handshake
Handshake --> Loop["消息循环/事件派发"]

图表来源 - websocket_ingress_runtime.v:16-30 - websocket_ingress_runtime.v:279-339 - websocket_ingress_runtime.v:413-482 - dispatch_session.v:11-35

章节来源 - websocket_ingress_runtime.v:16-30 - websocket_ingress_runtime.v:279-339 - websocket_ingress_runtime.v:413-482 - dispatch_session.v:11-35

事件类型与消息格式

  • 事件类型
  • open:连接建立时派发,携带 path/query/headers/remote_addr/rooms/metadata/presence
  • message:文本/二进制帧到达时派发,opcode 为 text/binary
  • close:对端或本地触发关闭时派发,携带 code/reason
  • 帧结构关键字段
  • mode:'websocket' 或 'websocket_dispatch'
  • event:'open'/'message'/'close'/'accept'/'done'/'error'
  • id/request_id/trace_id:追踪标识
  • opcode/data:消息载荷(binary 使用 base64)
  • rooms/metadata:当前连接所在房间与元数据
  • presence:房间成员、成员元数据、计数、用户列表快照
  • 命令列表(worker 返回)
  • send/send_to:向指定连接发送
  • join/leave:加入/离开房间
  • broadcast:向房间广播(可排除某连接)
  • close:主动关闭目标连接
  • set_meta/clear_meta:设置/清除连接元数据
classDiagram
class WorkerWebSocketFrame {
+string mode
+string event
+string id
+string request_id
+string trace_id
+string opcode
+string data
+map~string,string~ query
+map~string,string~ headers
+string remote_addr
+string path
+[]string rooms
+map~string,string~ metadata
+map~string,[]string~ room_members
+map~string,map~string,string~~ member_metadata
+map~string,int~ room_counts
+map~string,[]string~ presence_users
}
class Command {
+string event
+string id
+string target_id
+string room
+string data
+string opcode
+int code
+string reason
+string except_id
+string key
+string value
}
WorkerWebSocketFrame --> Command : "commands[]"

图表来源 - types.v:11-120 - hub_runtime.v:369-436

章节来源 - types.v:11-120 - hub_runtime.v:369-436 - WEBSOCKET_PHASE2_IMPLEMENTATION_PLAN.md:221-293

连接生命周期与状态机

  • 状态机阶段
  • opening → open:握手完成且标记开放
  • open → closing:收到 close 或由 worker 发起关闭
  • closing → closed:清理完成
  • 关键行为
  • can_process_messages:仅 open 且未通知关闭时可处理消息
  • can_send:open 且未通知关闭且非 worker 发起关闭时可发送
  • can_queue:opening/open 且未通知关闭时可入队
  • mark_open/mark_closing/begin_peer_close/begin_cleanup:受互斥锁保护的状态迁移
  • 连接注册与清理
  • register_conn/unregister_conn:维护 conns/conn_rooms/room_members/conn_meta/pending
  • cleanup_conn:删除连接、房间成员、元数据与待发消息
stateDiagram-v2
[*] --> opening
opening --> open : "mark_open()"
open --> closing : "begin_peer_close()/begin_worker_close()"
closing --> closed : "begin_cleanup()"
open --> open : "can_process_messages()"
open --> open : "can_send()/can_queue()"

图表来源 - types.v:11-120 - runtime.v:24-47

章节来源 - types.v:11-120 - runtime.v:24-47

房间系统与消息广播

  • 房间成员管理
  • join/leave:维护 room_members 与 conn_rooms 双向映射
  • rooms_snapshot/meta_snapshot:查询连接所在房间与元数据
  • presence_snapshot:聚合房间成员、成员元数据、计数与用户列表
  • 广播与定向发送
  • hub_broadcast:遍历房间成员,跳过 except_id,已连接直接写,未连接入队
  • hub_send_to:单发,支持入队与延迟写入
  • broadcast_dispatch:将 info 帧派发到房间内所有连接的 worker,再转发命令
flowchart TD
A["广播请求"] --> B["查找房间成员"]
B --> C{"是否已连接?"}
C --> |是| D["立即写入 client"]
C --> |否| E["入队 pending"]
D --> F["统计 delivered++"]
E --> F
F --> G["返回 delivered 数量"]

图表来源 - runtime.v:259-301 - runtime.v:303-342 - hub_runtime.v:217-251

章节来源 - runtime.v:259-301 - runtime.v:303-342 - hub_runtime.v:217-251

事件订阅与命令执行(Phase 2)

  • 事件构建与派发
  • build_frame:封装 method/path/query/headers/remote_addr/rooms/metadata/presence 等上下文
  • dispatch_event:将事件帧提交给 worker(inproc vjsx 或 php-worker)
  • 命令执行与失败回退
  • command_result:执行命令,支持 has_close/failures
  • followup_failure:根据失败情况决定是否关闭连接及关闭码/原因
  • 消息处理闭环
  • on_message:校验 opcode,构建 message 帧,派发并执行命令
  • on_close:派发 close 帧,执行最终命令,清理资源
sequenceDiagram
participant C as "客户端"
participant D as "分发会话"
participant H as "Hub"
participant W as "Worker"
C->>D : text/binary frame
D->>H : presence/rooms/metadata
D->>W : dispatch_event(message_frame)
W-->>D : commands[]
D->>H : command_result(commands)
alt has_close
D-->>C : close(code, reason)
else failures
D->>H : followup_failure(...)
H-->>D : ?close_frame
D-->>C : close(code, reason)
else ok
D-->>C : 继续监听
end

图表来源 - dispatch_session.v:126-168 - hub_runtime.v:115-134

章节来源 - dispatch_session.v:126-168 - hub_runtime.v:115-134

连接管理与会话亲和性

  • 连接注册
  • register_conn:保存 worker_socket、method、path、query、headers、remote_addr、client、lifecycle
  • 亲和性与路由
  • Phase 1:基于 worker 选择的长连接,保持同一 worker 会话
  • Phase 2:vhttpd 持有连接,按事件选择可用 worker,适合水平扩展
  • 元数据与会话状态
  • set_meta/clear_meta:连接级键值存储
  • rooms:连接加入的房间集合
  • presence:房间成员与用户视图

章节来源 - runtime.v:49-68 - runtime.v:168-197 - runtime.v:199-242

错误处理与断线恢复策略

  • 错误分类与响应
  • worker 返回 error/close/done 帧,vhttpd 转换为 HTTP 错误或 WebSocket close
  • 不支持的 opcode 直接关闭连接(1003)
  • 超时与重试
  • 读/写超时由底层网络控制,建议在客户端实现指数退避重连
  • 断线恢复
  • 客户端侧:捕获 close 事件,延迟重连,必要时重建房间与元数据
  • 服务端侧:on_close 派发 close 事件,允许 worker 做最后清理

章节来源 - websocket_ingress_runtime.v:103-160 - websocket_ingress_runtime.v:223-277 - dispatch_session.v:184-203

客户端实现指南

  • 基本流程
  • 建立连接,监听 open/message/close/error
  • 发送文本或二进制帧(二进制需 base64 编码)
  • 处理服务器关闭码与原因
  • 示例应用
  • 前端演示脚本位于 examples/public/websocket_echo_app.js
  • 配置文件 examples/config/websocket-echo.toml 用于快速启动 echo 服务

章节来源 - websocket_echo_app.js:1-45 - websocket_echo.toml:1-28

依赖关系分析

  • 内部依赖
  • websocket_ingress_runtime.v 依赖 ws 模块(分发会话、Hub、类型)
  • ws.dispatch_session 依赖 ws.hub_runtime 与 ws.runtime
  • ws.hub_runtime 依赖 upstream.transport 的帧构造与派发接口
  • 外部依赖
  • net.websocket:握手、帧解析、ping/pong、关闭生命周期
  • sync:互斥锁、并发安全
  • veb:HTTP 上下文与结果封装
graph LR
Ingress["websocket_ingress_runtime.v"] --> WS["ws.* (dispatch/hub/runtime/types)"]
WS --> Transport["upstream.transport"]
WS --> NetWS["net.websocket"]
WS --> Sync["sync"]
Ingress --> Veb["veb"]

图表来源 - websocket_ingress_runtime.v:1-15 - dispatch_session.v:1-8 - hub_runtime.v:1-6 - runtime.v:1-5 - types.v:1-8

章节来源 - websocket_ingress_runtime.v:1-15 - dispatch_session.v:1-8 - hub_runtime.v:1-6 - runtime.v:1-5 - types.v:1-8

性能考虑

  • 连接与命令批处理
  • 使用 Hub 的 pending 队列避免阻塞写入,flush_pending 在连接开放后批量发送
  • 广播优化
  • 先收集目标,再逐条发送,减少锁竞争
  • 读写分离
  • send_mu 独立于 mu,降低发送路径锁冲突
  • 事件分发
  • Phase 2 将业务逻辑解耦到 worker,提升可扩展性
  • 观察与诊断
  • 利用 admin 快照查看活跃连接、房间与成员分布

[本节为通用指导,无需具体文件引用]

故障排查指南

  • 常见问题
  • 握手失败:检查 Upgrade/Key/Connection 头是否正确
  • 不支持的帧类型:确保只发送 text/binary
  • 连接无响应:确认 worker 返回 done/accept/close/error
  • 定位手段
  • 查看 runtime_trace 日志(ws.session.start/enter/exit 等)
  • 使用 admin 快照查看连接与房间状态
  • 恢复步骤
  • 客户端重连并重建房间/元数据
  • 服务端检查 worker 健康与命令执行结果

章节来源 - websocket_ingress_runtime.v:103-160 - websocket_ingress_runtime.v:223-277 - hub_runtime.v:438-564

结论

vhttpd 的 WebSocket 方案通过 Phase 1 与 Phase 2 双模式兼顾简单与可扩展性。Phase 1 适合快速原型与简单场景;Phase 2 将连接所有权与业务逻辑解耦,便于横向扩展与高可用部署。结合 Hub 的房间与元数据能力,可实现高效的实时通信与广播。配合完善的错误处理与诊断工具,可在生产环境稳定运行。

[本节为总结,无需具体文件引用]

附录

消息格式示例(Phase 2)

  • 请求帧(event=message)
  • mode: "websocket_dispatch"
  • event: "message"
  • id/request_id/trace_id: 追踪标识
  • path/query/headers/remote_addr: 请求上下文
  • opcode: "text"/"binary"
  • data: 文本或 base64 编码的二进制
  • rooms/metadata/presence: 房间与存在性快照
  • 响应帧(event=result)
  • commands: 命令列表(send/send_to/join/leave/broadcast/close/set_meta/clear_meta)
  • 错误帧(event=error)
  • error_class/error: 错误类别与描述

章节来源 - WEBSOCKET_PHASE2_IMPLEMENTATION_PLAN.md:221-293

事件总线与多节点扩展

  • 当前范围
  • 单节点 Hub,跨 worker 扇出
  • 未来扩展
  • 可选外部总线适配器(Redis/NATS)实现多节点扇出
  • 房间分片、持久化订阅、二进制帧路由等

章节来源 - WEBSOCKET_EVENT_BUS_PLAN.md:405-444

代理、负载均衡与高可用配置

  • 代理与负载均衡
  • 使用反向代理(如 nginx/Traefik)进行 TCP 层负载均衡,确保同一会话粘性(sticky session)
  • 对于 Phase 2,由于连接由 vhttpd 持有,粘性策略应基于连接 ID 或源 IP
  • 高可用
  • 多实例部署,结合外部总线适配器实现跨节点广播
  • 健康检查与优雅关闭,确保连接迁移与资源释放

[本节为概念性内容,无需具体文件引用]