SSE 服务器端实时推送
简介
HttpServer 内置 SSE (Server-Sent Events) 支持,可实现服务器向客户端实时推送消息。适用于:
- 实时通知
- 在线聊天
- 数据监控
- 进度推送
客户端请求
客户端使用 cSSEClient 连接:
vb
Private WithEvents SSE As cSSEClient
Private Sub Connect()
Set SSE = New cSSEClient
SSE.Connect "http://localhost:8080/events"
End Sub
Private Sub SSE_OnMessage(EventName As String, Data As String, Id As String)
Debug.Print "收到: " & EventName & " = " & Data
End Sub服务端实现
基础推送
vb
' 在控制器中推送消息
Public Sub Events(ctx As cHttpServerContext)
' 使用 SendPack 快捷发送
ctx.SSE.SendPack "message", "Hello World", ctx.ClientInfo.hSocket
' 发送 JSON 数据
Dim data As New Dictionary
data("time") = Now
data("status") = "ok"
ctx.SSE.SendPack "data", Json.Encode(data), ctx.ClientInfo.hSocket
' 使用 Data + Send 自定义数据结构
ctx.SSE.Data.Add "type", "alert"
ctx.SSE.Data.Add "message", "系统维护通知"
ctx.SSE.Send ctx.ClientInfo.hSocket
End Sub广播消息
vb
' cNotificationController.cls
' 发送给所有连接(不传 hSocket 即广播)
Public Sub Broadcast(ctx As cHttpServerContext)
Dim msg As String
msg = ctx.Request.Form("message")
' 广播到所有 SSE 客户端
ctx.SSE.SendPack "notification", msg
ctx.Response.Json Nothing, 0, "已广播"
End Sub
' 发送给指定用户
Public Sub SendToUser(ctx As cHttpServerContext)
Dim userId As String, msg As String
userId = ctx.Request.Form("user_id")
msg = ctx.Request.Form("message")
' 通过链式调用发送给指定用户
ctx.SSE.ToUser(userId).SendPack "private", msg
ctx.Response.Json Nothing, 0, "已发送"
End Sub实时数据流
注意: SSE 是事件驱动模式,不适合在控制器中使用
Do While循环轮询。 应使用定时器(如 cTimer)定期推送数据,而非阻塞式循环。
vb
' cMonitorController.cls
' 由定时器触发推送(推荐方式)
Public Sub PushStats(ctx As cHttpServerContext)
' 收集系统数据
Dim data As New Dictionary
data("cpu") = GetCPUUsage()
data("memory") = GetMemoryUsage()
data("time") = Now
' 推送给所有在线 SSE 客户端
ctx.SSE.SendPack "stats", Json.Encode(data)
End Sub进度推送
vb
' cTaskController.cls
' 由定时器或回调触发推送进度
Public Sub PushProgress(ctx As cHttpServerContext)
Dim taskId As String
taskId = ctx.Request.Form("task_id")
Dim percent As Long
percent = CLng(ctx.Request.Form("percent"))
Dim progress As New Dictionary
progress("percent") = percent
progress("task_id") = taskId
' 推送给请求的客户端
ctx.SSE.SendPack "progress", Json.Encode(progress), ctx.ClientInfo.hSocket
End Sub
Public Sub PushComplete(ctx As cHttpServerContext)
ctx.SSE.SendPack "complete", "{\"status\":\"done\"}", ctx.ClientInfo.hSocket
End Sub完整聊天示例
vb
' ========== 服务端 ==========
' cChatController.cls
Option Explicit
' GET /chat/stream
Public Sub Stream(ctx As cHttpServerContext)
' 检查登录
If Not ctx.Session.Exists("user_id") Then
ctx.Response.State401 "请先登录"
Exit Sub
End If
' 注册到聊天室(SSE 连接由框架自动管理,无需手动设置头)
Dim userId As String, username As String
userId = ctx.Session("user_id")
username = ctx.Session("username")
' 绑定用户(后续可按用户名推送)
ctx.SSE.BindUser ctx.ClientInfo.hSocket, userId
' 发送欢迎消息
ctx.SSE.SendPack "system", "{\"msg\":\"欢迎 " & username & " 加入聊天室\"}", ctx.ClientInfo.hSocket
End Sub
' POST /chat/send
Public Sub SendMsg(ctx As cHttpServerContext)
Dim msg As String
msg = ctx.Request.Form("message")
Dim username As String
username = ctx.Session("username")
' 广播给所有用户(不传 hSocket 即广播)
Dim data As String
data = "{\"user\":\"" & username & "\",\"msg\":\"" & msg & "\"}"
ctx.SSE.SendPack "message", data
ctx.Response.Json Nothing, 0, "已发送"
End Sub
' ========== 客户端 ==========
Private WithEvents SSE As cSSEClient
Private Sub JoinChat()
Set SSE = New cSSEClient
SSE.Connect "http://localhost:8080/chat/stream"
End Sub
Private Sub SendMessage(msg As String)
Dim http As New cHttpClient
http.RequestDataForm("message") = msg
http.SendPost "http://localhost:8080/chat/send"
End Sub
Private Sub SSE_OnMessage(EventName As String, Data As String, Id As String)
Select Case EventName
Case "system"
' 显示系统消息
ShowSystemMessage Data
Case "message"
' 显示聊天消息
ShowChatMessage Data
End Select
End Sub服务端 API 参考
Start
启动 SSE 服务,绑定路径和事件处理器。
注意:
Start是cSSE类的方法,仅在服务启动时调用。控制器中通过ctx.SSE(cSSEContext)无法调用此方法。
vb
Public Function Start(Optional MatchPath As String, Optional EventsHandler As Object) As Boolean参数:
MatchPath- 匹配的请求路径(为空则匹配所有)EventsHandler- 事件处理器对象,需实现OnConnect(Context)和OnClose(Context)方法
示例:
vb
' 启动 SSE,监听 /events 路径
Set SSE = New cSSE
SSE.Start "/events", Me ' Me 实现了 OnConnect/OnClose
' 在事件处理器中
Public Sub OnConnect(ctx As cHttpServerContext)
Debug.Print "SSE 客户端连接: " & ctx.ClientInfo.IP
End Sub
Public Sub OnClose(ctx As cHttpServerContext)
Debug.Print "SSE 客户端断开: " & ctx.ClientInfo.IP
End SubSend / SendPack
发送消息给 SSE 客户端。
vb
' 自定义数据发送
Public Function Send(Optional ByVal hSocket As Long) As Boolean
' 快捷打包发送(action + content 格式)
Public Function SendPack(Action As String, Content As Variant, Optional hSocket As Long) As Boolean说明: Send 使用共享 Data 字典构建消息体,SendPack 自动封装 {"action":..., "content":...} 格式。两者都支持指定 hSocket 发送给特定客户端,或省略(由 ToUser/ToGroup 链式设定目标)。
Send 重入安全: Send 方法在编码前会将共享 Data 快照到局部变量,发送过程中即使触发重入调用也不会导致数据错乱。
示例:
vb
' 使用 Send 发送自定义数据
SSE.Data.Add "type", "alert"
SSE.Data.Add "message", "系统维护通知"
SSE.Send hSocket
' 使用 SendPack 快捷发送
SSE.SendPack "notification", "您有新消息", hSocket
' 链式调用发送给指定用户
SSE.ToUser("admin").SendPack "private", "欢迎回来"CloseClient
关闭指定 SSE 客户端连接。
vb
Public Function CloseClient(Optional ByVal hSocket As Long) As Boolean说明: 无论通过参数还是 ToUser 链式调用,都会执行完整清理流程:
- 触发
OnClose用户事件 - 清除 SSE 上下文引用
- 从 Clients 字典移除
- 清理用户/分组映射
- 关闭 Socket 连接,触发 cClientCallback 的完整清理流程
示例:
vb
' 关闭指定客户端
SSE.CloseClient hSocket
' 链式关闭指定用户
SSE.ToUser("admin").CloseClientBindUser / GetUser / GetClientByUser
管理用户与 Socket 的映射关系。
vb
Public Function BindUser(ByVal hSocket As Long, ByVal User As String) As Boolean
Public Function GetUser(ByVal hSocket As Long) As String
Public Function GetClientByUser(ByVal User As String) As Long示例:
vb
' 绑定用户
SSE.BindUser hSocket, "user_123"
' 根据用户名查找 Socket
Dim sock As Long
sock = SSE.GetClientByUser("user_123")
' 根据 Socket 查找用户名
Dim user As String
user = SSE.GetUser(hSocket)ToUser / ToGroup
链式调用指定发送目标。
vb
Public Function ToUser(ByVal User As String) As cSSEContext
Public Function ToGroup(ByVal Name As String) As cSSEContext说明: 返回 cSSEContext 自身,同时设置内部目标 hSocket。后续调用 Send/SendPack/CloseClient 时无需再传 hSocket。
示例:
vb
' 发送给指定用户
ctx.SSE.ToUser("admin").SendPack "msg", "Hello Admin"
' 关闭指定用户连接
ctx.SSE.ToUser("admin").CloseClientClientCount
当前在线 SSE 客户端数量(只读)。
vb
Public Property Get ClientCount() As Long示例:
vb
Debug.Print "在线 SSE 客户端: " & SSE.ClientCount最后更新: 2026-06-13