WebSocket 开发文档
目录
概述
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。新版 WebSocket 类库提供了分离的客户端和服务端实现,支持文本和二进制消息传输,具有高效的缓冲区管理和完善的错误处理机制。
主要特性
- 分离架构 - 客户端 (
cWebSocketClient) 和服务端 (cWebSocketServer) 独立实现 - 协议支持 - 完整实现 WebSocket 协议 (RFC 6455)
- 消息类型 - 支持文本消息和二进制消息
- 帧解析器 -
cWebSocketFrame类专门处理帧解析和构建 - 高效缓冲 -
cByteBuffer类提供预分配和自动增长策略 - 事件驱动 - 通过事件机制处理所有网络事件
- 广播功能 - 服务端支持向所有客户端广播消息
项目结构
Websocket/
├── Client/
│ ├── frmClient.frm # 客户端窗体
│ ├── WsClient.vbp # 客户端项目
│ └── WsClient.vbw
├── Server/
│ ├── frmServer.frm # 服务端窗体
│ ├── WsServer.vbp # 服务端项目
│ └── WsServer.vbw
└── README.md # 示例说明类库架构
newWebsocket/
├── mWebSocketUtils.bas # 公共工具模块 (UTF-8, Base64, SHA1, 枚举定义)
├── cByteBuffer.cls # 高效字节缓冲区:预分配、自动增长、最小内存操作
├── cWebSocketFrame.cls # WebSocket 帧解析器:只读解析、分离的unmask操作
├── cWebSocketClient.cls # WebSocket 客户端
├── cWebSocketServer.cls # WebSocket 服务端
└── cWebSocketServerClient.cls # 服务端客户端连接信息快速开始
环境要求
- Visual Basic 6.0 或更高版本
- VBMAN.dll 库文件(位于
..\..\..\vbman\dist\DLL\)
引用库
- 打开项目
WsClient.vbp或WsServer.vbp - 确保已引用
VBMANLIB库 - 检查引用路径:
..\..\..\vbman\dist\DLL\VBMAN.dll
运行示例
启动服务端
- 打开
Server/WsServer.vbp - 运行项目
- 点击"启动服务"按钮
- 默认监听端口 8080
- 打开
启动客户端
- 打开
Client/WsClient.vbp - 运行项目
- 输入服务器地址
ws://127.0.0.1:8080 - 点击"连接"按钮
- 连接成功后可发送消息
- 打开
测试通信
- 在客户端输入消息并点击"发送"
- 服务端会回显消息
- 发送 "broadcast" 可触发服务端广播功能
WebSocket 客户端

创建客户端
vb
Private WithEvents m_WsClient As cWebSocketClient
Private Sub InitializeClient()
If m_WsClient Is Nothing Then
Set m_WsClient = New cWebSocketClient
End If
End Sub连接到服务器
vb
Private Sub ConnectToServer(ByVal sURL As String)
On Error GoTo EH
InitializeClient()
m_WsClient.Connect sURL
LogMessage "正在连接到: " & sURL
Exit Sub
EH:
LogMessage "连接失败: " & Err.Description
End Sub参数说明:
sURL: WebSocket 服务器 URL- 格式:
ws://host:port或wss://host:port(加密) - 示例:
ws://127.0.0.1:8080
- 格式:
发送文本消息
vb
Private Sub SendTextMessage(sMessage As String)
On Error GoTo EH
If Not m_WsClient Is Nothing And m_WsClient.State = WS_STATE_OPEN Then
m_WsClient.SendText sMessage
LogMessage "已发送: " & sMessage
End If
Exit Sub
EH:
LogMessage "发送失败: " & Err.Description
End Sub发送二进制消息
vb
Private Sub SendBinaryMessage(Data() As Byte)
On Error GoTo EH
If Not m_WsClient Is Nothing And m_WsClient.State = WS_STATE_OPEN Then
m_WsClient.SendBinary Data
LogMessage "已发送二进制数据: " & (UBound(Data) + 1) & " 字节"
End If
Exit Sub
EH:
LogMessage "发送失败: " & Err.Description
End Sub发送 Ping 帧
vb
Private Sub SendPing(Optional Data() As Byte)
On Error GoTo EH
If Not m_WsClient Is Nothing And m_WsClient.State = WS_STATE_OPEN Then
m_WsClient.Ping Data
LogMessage "已发送 Ping"
End If
Exit Sub
EH:
LogMessage "发送 Ping 失败: " & Err.Description
End Sub断开连接
vb
Private Sub Disconnect(Optional ByVal Code As WsCloseCode = WS_CLOSE_NORMAL, Optional ByVal Reason As String = "")
If Not m_WsClient Is Nothing Then
m_WsClient.CloseConnection Code, Reason
LogMessage "已断开连接"
End If
End Sub关闭码说明:
WS_CLOSE_NORMAL(1000): 正常关闭WS_CLOSE_GOING_AWAY(1001): 端点离开WS_CLOSE_PROTOCOL_ERROR(1002): 协议错误WS_CLOSE_UNSUPPORTED(1003): 不支持的数据类型WS_CLOSE_NO_STATUS(1005): 无状态码WS_CLOSE_ABNORMAL(1006): 异常关闭WS_CLOSE_INVALID_PAYLOAD(1007): 无效数据WS_CLOSE_POLICY_VIOLATION(1008): 策略违规WS_CLOSE_MESSAGE_TOO_BIG(1009): 消息过大WS_CLOSE_MANDATORY_EXT(1010): 缺少扩展WS_CLOSE_INTERNAL_ERROR(1011): 内部错误WS_CLOSE_TLS_HANDSHAKE(1015): TLS 握手失败
完整示例
参考 Client/frmClient.frm 文件:
vb
Private Sub cmdConnect_Click()
On Error GoTo EH
If m_WsClient Is Nothing Then
Set m_WsClient = New cWebSocketClient
End If
m_WsClient.Connect txtURL.Text
LogMessage "正在连接到: " & txtURL.Text
cmdConnect.Enabled = False
Exit Sub
EH:
LogMessage "连接失败: " & Err.Description
End Sub
Private Sub cmdSend_Click()
On Error GoTo EH
If Not m_WsClient Is Nothing And m_WsClient.State = WS_STATE_OPEN Then
m_WsClient.SendText txtMessage.Text
LogMessage "已发送: " & txtMessage.Text
End If
Exit Sub
EH:
LogMessage "发送失败: " & Err.Description
End Sub
Private Sub UpdateUI(bConnected As Boolean)
cmdConnect.Enabled = Not bConnected
cmdDisconnect.Enabled = bConnected
cmdSend.Enabled = bConnected
End SubWebSocket 服务器

创建服务器
vb
Private WithEvents m_WsServer As cWebSocketServer
Private Sub InitializeServer()
If m_WsServer Is Nothing Then
Set m_WsServer = New cWebSocketServer
End If
End Sub启动监听
vb
Private Sub StartServer(ByVal lPort As Long)
On Error GoTo EH
InitializeServer()
m_WsServer.Listen lPort
LogMessage "WebSocket 服务器已启动,监听端口: " & lPort
Exit Sub
EH:
LogMessage "启动服务失败: " & Err.Description
End Sub停止服务
vb
Private Sub StopServer()
If Not m_WsServer Is Nothing Then
m_WsServer.StopServer
LogMessage "WebSocket 服务器已停止"
End If
End Sub发送消息给指定客户端
vb
Private Sub SendToClient(ByVal ClientID As String, sMessage As String)
On Error GoTo EH
m_WsServer.SendText ClientID, sMessage
LogMessage "已向客户端 " & ClientID & " 发送消息: " & sMessage
Exit Sub
EH:
LogMessage "发送失败: " & Err.Description
End Sub发送二进制消息给指定客户端
vb
Private Sub SendBinaryToClient(ByVal ClientID As String, Data() As Byte)
On Error GoTo EH
m_WsServer.SendBinary ClientID, Data
LogMessage "已向客户端 " & ClientID & " 发送二进制数据: " & (UBound(Data) + 1) & " 字节"
Exit Sub
EH:
LogMessage "发送失败: " & Err.Description
End Sub广播消息
vb
Private Sub BroadcastMessage(sMessage As String, Optional ByVal ExcludeClientID As String = "")
On Error GoTo EH
m_WsServer.BroadcastText sMessage, ExcludeClientID
LogMessage "已广播消息: " & sMessage
Exit Sub
EH:
LogMessage "广播失败: " & Err.Description
End Sub参数说明:
sMessage: 要广播的消息ExcludeClientID: 可选,排除指定的客户端 ID(不接收广播)
广播二进制消息
vb
Private Sub BroadcastBinaryMessage(Data() As Byte, Optional ByVal ExcludeClientID As String = "")
On Error GoTo EH
m_WsServer.BroadcastBinary Data, ExcludeClientID
LogMessage "已广播二进制数据: " & (UBound(Data) + 1) & " 字节"
Exit Sub
EH:
LogMessage "广播失败: " & Err.Description
End Sub断开指定客户端
vb
Private Sub DisconnectClient(ByVal ClientID As String, Optional ByVal Code As WsCloseCode = WS_CLOSE_NORMAL, Optional ByVal Reason As String = "")
On Error GoTo EH
m_WsServer.DisconnectClient ClientID, Code, Reason
LogMessage "已断开客户端 " & ClientID
Exit Sub
EH:
LogMessage "断开客户端失败: " & Err.Description
End Sub获取客户端信息
vb
Private Sub GetClientInfo(ByVal ClientID As String)
Dim oClient As cWebSocketServerClient
Set oClient = m_WsServer.GetClient(ClientID)
If Not oClient Is Nothing Then
LogMessage "客户端 ID: " & oClient.ID
LogMessage "远程地址: " & oClient.RemoteAddress
LogMessage "远程端口: " & oClient.RemotePort
LogMessage "连接时间: " & oClient.ConnectedTime
End If
End Sub完整示例
参考 Server/frmServer.frm 文件:
vb
Private Sub cmdStart_Click()
On Error GoTo EH
If m_WsServer Is Nothing Then
Set m_WsServer = New cWebSocketServer
End If
m_WsServer.Listen CLng(txtPort.Text)
LogMessage "WebSocket 服务器已启动,监听端口: " & txtPort.Text
cmdStart.Enabled = False
cmdStop.Enabled = True
Exit Sub
EH:
LogMessage "启动服务失败: " & Err.Description
End Sub
Private Sub m_WsServer_OnClientTextMessage(ByVal ClientID As String, ByVal Message As String)
LogMessage "收到来自 " & ClientID & " 的文本消息: " & Message
' 回显消息
m_WsServer.SendText ClientID, "服务器收到: " & Message
' 如果消息是 "broadcast",则广播给所有客户端
If LCase$(Message) = "broadcast" Then
m_WsServer.BroadcastText "这是一条广播消息,来自客户端 " & ClientID, ClientID
LogMessage "已向所有客户端发送广播消息"
End If
End SubAPI 参考
cWebSocketClient 属性
| 属性名 | 类型 | 说明 |
|---|---|---|
State | WsState | 连接状态(参见状态常量) |
URL | String | 连接的 WebSocket URL |
ReadyState | WsState | ReadyState 属性(同 State) |
cWebSocketClient 方法
Connect
vb
m_WsClient.Connect URL连接到 WebSocket 服务器。
参数:
URL: WebSocket 服务器 URL
SendText
vb
m_WsClient.SendText Message发送文本消息。
参数:
Message: 文本消息内容
SendBinary
vb
m_WsClient.SendBinary Data()发送二进制消息。
参数:
Data: 字节数组
Ping
vb
m_WsClient.Ping [Data()]发送 Ping 帧。
参数:
Data: 可选,附加的数据
CloseConnection
vb
m_WsClient.CloseConnection [Code], [Reason]关闭连接。
参数:
Code: 可选,关闭码(默认 WS_CLOSE_NORMAL)Reason: 可选,关闭原因
cWebSocketServer 方法
Listen
vb
m_WsServer.Listen Port开始监听指定端口。
参数:
Port: 监听端口号
StopServer
vb
m_WsServer.StopServer停止服务并断开所有客户端。
SendText
vb
m_WsServer.SendText ClientID, Message发送文本消息给指定客户端。
参数:
ClientID: 客户端 IDMessage: 文本消息内容
SendBinary
vb
m_WsServer.SendBinary ClientID, Data()发送二进制消息给指定客户端。
参数:
ClientID: 客户端 IDData: 字节数组
BroadcastText
vb
m_WsServer.BroadcastText Message, [ExcludeClientID]向所有客户端广播文本消息。
参数:
Message: 文本消息内容ExcludeClientID: 可选,排除的客户端 ID
BroadcastBinary
vb
m_WsServer.BroadcastBinary Data(), [ExcludeClientID]向所有客户端广播二进制消息。
参数:
Data: 字节数组ExcludeClientID: 可选,排除的客户端 ID
DisconnectClient
vb
m_WsServer.DisconnectClient ClientID, [Code], [Reason]断开指定客户端。
参数:
ClientID: 客户端 IDCode: 可选,关闭码Reason: 可选,关闭原因
GetClient
vb
Set oClient = m_WsServer.GetClient(ClientID)获取客户端对象。
参数:
ClientID: 客户端 ID
返回: cWebSocketServerClient 对象
状态常量
| 常量 | 值 | 说明 |
|---|---|---|
WS_STATE_CONNECTING | 0 | 正在连接 |
WS_STATE_OPEN | 1 | 已连接 |
WS_STATE_CLOSING | 2 | 正在关闭 |
WS_STATE_CLOSED | 3 | 已关闭 |
事件说明
客户端事件
OnOpen
vb
Private Sub m_WsClient_OnOpen()连接成功建立时触发。
OnClose
vb
Private Sub m_WsClient_OnClose(ByVal Code As WsCloseCode, ByVal Reason As String)连接关闭时触发。
参数:
Code: 关闭码Reason: 关闭原因
OnTextMessage
vb
Private Sub m_WsClient_OnTextMessage(ByVal Message As String)收到文本消息时触发。
参数:
Message: 文本消息内容
OnBinaryMessage
vb
Private Sub m_WsClient_OnBinaryMessage(Data() As Byte)收到二进制消息时触发。
参数:
Data: 二进制数据数组
OnError
vb
Private Sub m_WsClient_OnError(ByVal Description As String)发生错误时触发。
参数:
Description: 错误描述
OnPong
vb
Private Sub m_WsClient_OnPong(Data() As Byte)收到 Pong 响应时触发。
参数:
Data: Pong 数据
服务端事件
OnStart
vb
Private Sub m_WsServer_OnStart(ByVal Port As Long)服务启动时触发。
参数:
Port: 监听端口号
OnStop
vb
Private Sub m_WsServer_OnStop()服务停止时触发。
OnClientConnect
vb
Private Sub m_WsServer_OnClientConnect(ByVal ClientID As String, ByVal RemoteAddress As String, ByVal RemotePort As Long)新客户端连接时触发。
参数:
ClientID: 客户端 IDRemoteAddress: 客户端 IP 地址RemotePort: 客户端端口
OnClientDisconnect
vb
Private Sub m_WsServer_OnClientDisconnect(ByVal ClientID As String, ByVal Reason As String)客户端断开连接时触发。
参数:
ClientID: 客户端 IDReason: 断开原因
OnClientTextMessage
vb
Private Sub m_WsServer_OnClientTextMessage(ByVal ClientID As String, ByVal Message As String)收到客户端文本消息时触发。
参数:
ClientID: 客户端 IDMessage: 文本消息内容
OnClientBinaryMessage
vb
Private Sub m_WsServer_OnClientBinaryMessage(ByVal ClientID As String, Data() As Byte)收到客户端二进制消息时触发。
参数:
ClientID: 客户端 IDData: 二进制数据数组
OnError
vb
Private Sub m_WsServer_OnError(ByVal Description As String)发生错误时触发。
参数:
Description: 错误描述
高级特性
客户端自动重连
实现客户端自动重连机制:
vb
Private WithEvents tmrReconnect As Timer
Private lReconnectAttempts As Long
Private Sub m_WsClient_OnClose(ByVal Code As WsCloseCode, ByVal Reason As String)
LogMessage "连接已关闭: " & Reason
' 非正常关闭时尝试重连
If Code <> WS_CLOSE_NORMAL Then
StartReconnectTimer
End If
End Sub
Private Sub StartReconnectTimer()
lReconnectAttempts = 0
Set tmrReconnect = New Timer
tmrReconnect.Interval = 3000 ' 3秒后重连
tmrReconnect.Enabled = True
End Sub
Private Sub tmrReconnect_Timer()
tmrReconnect.Enabled = False
If lReconnectAttempts < 5 Then
lReconnectAttempts = lReconnectAttempts + 1
LogMessage "尝试重连 (" & lReconnectAttempts & "/5)..."
m_WsClient.Connect txtURL.Text
Else
LogMessage "重连失败,已达到最大尝试次数"
End If
End Sub心跳保活
实现客户端和服务端的心跳保活:
vb
' 客户端端
Private WithEvents tmrHeartbeat As Timer
Private Sub m_WsClient_OnOpen()
LogMessage "已连接,启动心跳"
Set tmrHeartbeat = New Timer
tmrHeartbeat.Interval = 30000 ' 30秒
tmrHeartbeat.Enabled = True
End Sub
Private Sub tmrHeartbeat_Timer()
If m_WsClient.State = WS_STATE_OPEN Then
m_WsClient.Ping
LogMessage "发送心跳 Ping"
End If
End Sub
' 服务端端 - 记录最后活动时间
Private Sub m_WsServer_OnClientTextMessage(ByVal ClientID As String, ByVal Message As String)
' 记录客户端活动时间
Dim oClient As cWebSocketServerClient
Set oClient = m_WsServer.GetClient(ClientID)
If Not oClient Is Nothing Then
oClient.LastActivity = Now
End If
End Sub消息队列
实现消息队列确保消息顺序发送:
vb
Private colMessageQueue As Collection
Private bSending As Boolean
Private Sub InitializeQueue()
Set colMessageQueue = New Collection
bSending = False
End Sub
Private Sub EnqueueMessage(sMessage As String)
colMessageQueue.Add sMessage
If Not bSending Then
ProcessQueue
End If
End Sub
Private Sub ProcessQueue()
If colMessageQueue.Count > 0 And m_WsClient.State = WS_STATE_OPEN Then
bSending = True
' 获取队列中的第一条消息
Dim sMessage As String
sMessage = colMessageQueue(1)
colMessageQueue.Remove 1
' 发送消息
m_WsClient.SendText sMessage
Else
bSending = False
End If
End Sub
Private Sub m_WsClient_OnTextMessage(ByVal Message As String)
LogMessage "收到响应: " & Message
' 处理下一条消息
If colMessageQueue.Count > 0 Then
ProcessQueue
Else
bSending = False
End If
End Sub认证机制
实现简单的令牌认证:
vb
' 服务端 - 在连接时验证
Private Sub m_WsServer_OnClientConnect(ByVal ClientID As String, ByVal RemoteAddress As String, ByVal RemotePort As Long)
Dim oClient As cWebSocketServerClient
Set oClient = m_WsServer.GetClient(ClientID)
' 检查查询参数中的 token
Dim sToken As String
sToken = ExtractTokenFromClient(oClient)
If Not IsValidToken(sToken) Then
LogMessage "认证失败,断开客户端: " & ClientID
m_WsServer.DisconnectClient ClientID, WS_CLOSE_POLICY_VIOLATION, "Invalid token"
Exit Sub
End If
LogMessage "客户端认证成功: " & ClientID
End Sub
' 客户端 - 在 URL 中附加令牌
Private Sub ConnectWithToken(ByVal sURL As String, ByVal sToken As String)
Dim sURLWithToken As String
sURLWithToken = sURL & "?token=" & sToken
m_WsClient.Connect sURLWithToken
End Sub消息压缩
使用 Deflate 算法压缩消息:
vb
Private Sub SendCompressedMessage(sMessage As String)
Dim byOriginal() As Byte
Dim byCompressed() As Byte
' 转换为 UTF-8 字节数组
byOriginal = UTF8.GetBytes(sMessage)
' 压缩数据(需要实现 Deflate 压缩函数)
byCompressed = CompressData(byOriginal)
' 发送压缩后的数据
m_WsClient.SendBinary byCompressed
LogMessage "已发送压缩消息: " & (UBound(byOriginal) + 1) & " -> " & (UBound(byCompressed) + 1) & " 字节"
End Sub常见问题
Q1: 如何处理连接超时?
A: 使用定时器监控连接状态:
vb
Private WithEvents tmrConnect As Timer
Private Sub StartConnectTimer()
Set tmrConnect = New Timer
tmrConnect.Interval = 10000 ' 10秒超时
tmrConnect.Enabled = True
End Sub
Private Sub tmrConnect_Timer()
tmrConnect.Enabled = False
If m_WsClient.State = WS_STATE_CONNECTING Then
LogMessage "连接超时"
m_WsClient.CloseConnection WS_CLOSE_ABNORMAL, "Connection timeout"
UpdateUI False
End If
End Sub
Private Sub m_WsClient_OnOpen()
tmrConnect.Enabled = False
LogMessage "连接成功"
End SubQ2: 如何处理大消息?
A: 使用消息分块传输:
vb
Private Sub SendLargeMessage(sMessage As String)
Const MAX_CHUNK_SIZE As Long = 1024 ' 1KB 分块
Dim lLength As Long
Dim lOffset As Long
Dim sChunk As String
lLength = Len(sMessage)
lOffset = 1
Do While lOffset <= lLength
sChunk = Mid(sMessage, lOffset, MAX_CHUNK_SIZE)
m_WsClient.SendText sChunk
LogMessage "发送分块 " & (lOffset \ MAX_CHUNK_SIZE + 1) & ": " & Len(sChunk) & " 字节"
lOffset = lOffset + MAX_CHUNK_SIZE
' 短暂延迟
DoEvents
Sleep 50
Loop
End SubQ3: 如何限制客户端连接数?
A: 在服务端维护客户端计数:
vb
Private lMaxClients As Long
Private lCurrentClients As Long
Private Sub InitializeServer()
lMaxClients = 100 ' 最大客户端数
lCurrentClients = 0
End Sub
Private Sub m_WsServer_OnClientConnect(ByVal ClientID As String, ByVal RemoteAddress As String, ByVal RemotePort As Long)
If lCurrentClients >= lMaxClients Then
LogMessage "拒绝连接: 达到最大客户端数"
m_WsServer.DisconnectClient ClientID, WS_CLOSE_TRY_AGAIN_LATER, "Server full"
Exit Sub
End If
lCurrentClients = lCurrentClients + 1
LogMessage "客户端连接: " & ClientID & " (当前: " & lCurrentClients & "/" & lMaxClients & ")"
End Sub
Private Sub m_WsServer_OnClientDisconnect(ByVal ClientID As String, ByVal Reason As String)
lCurrentClients = lCurrentClients - 1
LogMessage "客户端断开: " & ClientID & " (当前: " & lCurrentClients & ")"
End SubQ4: 如何实现房间功能?
A: 使用客户端分组管理:
vb
Private colRooms As Collection
Private Sub InitializeRooms()
Set colRooms = New Collection
End Sub
' 加入房间
Private Sub JoinRoom(ByVal ClientID As String, ByVal sRoom As String)
Dim colClients As Collection
On Error Resume Next
Set colClients = colRooms(sRoom)
If colClients Is Nothing Then
Set colClients = New Collection
colRooms.Add colClients, sRoom
End If
On Error GoTo 0
colClients.Add ClientID, ClientID
LogMessage "客户端 " & ClientID & " 加入房间: " & sRoom
End Sub
' 向房间发送消息
Private Sub SendToRoom(ByVal sRoom As String, ByVal sMessage As String)
Dim colClients As Collection
Dim i As Long
On Error Resume Next
Set colClients = colRooms(sRoom)
On Error GoTo 0
If Not colClients Is Nothing Then
For i = 1 To colClients.Count
m_WsServer.SendText colClients(i), sMessage
Next i
End If
End SubQ5: 如何调试 WebSocket 通信?
A: 记录所有事件和详细日志:
vb
Private Sub LogWebSocketEvent(ByVal sEventType As String, ByVal sDetails As String)
Dim sLog As String
sLog = Format$(Now, "yyyy-mm-dd hh:mm:ss") & " [" & sEventType & "] " & sDetails
' 输出到日志窗口
txtLog.Text = txtLog.Text & sLog & vbCrLf
txtLog.SelStart = Len(txtLog.Text)
' 输出到调试窗口
Debug.Print sLog
' 可选: 写入文件
LogToFile sLog
End Sub
Private Sub LogToFile(sLog As String)
Dim nFile As Integer
nFile = FreeFile
Open App.Path & "\websocket.log" For Append As #nFile
Print #nFile, sLog
Close #nFile
End Sub最佳实践
- 资源清理:窗体卸载时调用
CloseConnection或StopServer释放资源 - 错误处理:所有网络操作都应包含错误处理
- 状态检查:发送消息前检查
State = WS_STATE_OPEN - 日志记录:记录关键事件便于调试和问题排查
- 超时处理:实现合理的连接和操作超时机制
- 心跳保活:定期发送 Ping 帧保持连接活跃
- 消息验证:接收消息时进行格式和长度验证
- 优雅关闭:使用正确的关闭码和原因信息
- 客户端限制:实现合理的客户端连接数限制
- 安全认证:在生产环境中实现认证机制
协议说明
WebSocket 握手流程
- 客户端请求
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13- 服务端响应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=帧结构
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+操作码
| 值 | 说明 |
|---|---|
| 0x0 | 连续帧 |
| 0x1 | 文本帧 |
| 0x2 | 二进制帧 |
| 0x8 | 关闭帧 |
| 0x9 | Ping 帧 |
| 0xA | Pong 帧 |
相关资源
- 项目目录:
Websocket/ - 客户端示例:
Client/frmClient.frm - 服务端示例:
Server/frmServer.frm - 依赖库:
VBMAN.dll - WebSocket 协议: RFC 6455
更新日志
- v2.0 - 新版类库,分离客户端/服务端,优化架构
- 分离的客户端 (
cWebSocketClient) 和服务端 (cWebSocketServer) 类 - 独立的帧解析器 (
cWebSocketFrame) - 高效的缓冲区管理 (
cByteBuffer) - 清晰的职责分离和错误处理
- 分离的客户端 (
- v1.0 - 初始版本