cWinsock 开发文档
目录
概述
cWinsock 是一个基于 Windows Socket API 的高级封装类,提供了简单易用的 VB6 网络编程接口。它支持 TCP 和 UDP 协议,可以轻松创建客户端和服务器端应用程序。
主要特性
- 多协议支持: 支持 TCP 和 UDP 协议
- 异步非阻塞: 使用异步 I/O 模型,不阻塞 UI 线程
- 多客户端管理: 服务器端自动管理多个客户端连接
- 事件驱动: 通过事件机制处理网络事件
- 错误处理: 完善的错误处理机制
项目结构
Winsock/
├── Form1.frm # 主窗体(服务器 + UDP 示例)
├── Client.frm # 客户端窗体
├── Module1.bas # 模块文件
├── Project1.vbp # 项目文件
└── README.md # 示例说明快速开始
环境要求
- Visual Basic 6.0 或更高版本
- VBMAN.dll 库文件(位于
..\..\vbman\dist\DLL\)
引用库
- 打开项目
Project1.vbp - 确保已引用
VBMANLIB库 - 检查引用路径是否正确:
..\..\vbman\dist\DLL\VBMAN.dll
基础代码结构
vb
' 声明 cWinsock 对象(带事件)
Private WithEvents m_oSocket As cWinsock
' 初始化对象
Set m_oSocket = New cWinsock
' 设置协议类型
m_oSocket.Protocol = sckTCPProtocol ' 或 sckUDPProtocolTCP 客户端
TCP 客户端用于连接到远程服务器,建立可靠的连接后进行双向通信。

创建 TCP 客户端
vb
Private WithEvents m_oClient As cWinsock
Private Sub InitializeClient()
If m_oClient Is Nothing Then
Set m_oClient = New cWinsock
m_oClient.Protocol = sckTCPProtocol
End If
End Sub连接到服务器
vb
Private Sub ConnectToServer(ByVal sHost As String, ByVal lPort As Long)
On Error GoTo EH
InitializeClient()
m_oClient.Connect sHost, lPort
LogMessage "正在连接到 " & sHost & ":" & lPort & "..."
Exit Sub
EH:
LogMessage "连接错误: " & Err.Description
End Sub参数说明:
sHost: 服务器 IP 地址或主机名(如 "127.0.0.1" 或 "example.com")lPort: 服务器端口号(如 8080)
发送数据
vb
Private Sub SendData(sData As String)
On Error GoTo EH
If Not m_oClient Is Nothing And m_oClient.State = sckConnected Then
m_oClient.SendData sData
LogMessage "已发送数据: " & sData
Else
LogMessage "未连接到服务器"
End If
Exit Sub
EH:
LogMessage "发送错误: " & Err.Description
End Sub断开连接
vb
Private Sub Disconnect()
If Not m_oClient Is Nothing Then
m_oClient.Close_
LogMessage "客户端已断开连接"
End If
End Sub完整示例
参考 Client.frm 文件,这是一个完整的 TCP 客户端实现:
vb
Private Sub cmdClientConnect_Click()
On Error GoTo EH
If m_oClient Is Nothing Then
Set m_oClient = New cWinsock
m_oClient.Protocol = sckTCPProtocol
End If
m_oClient.Connect txtClientHost.Text, CLng(txtClientPort.Text)
LogMessage "正在连接到 " & txtClientHost.Text & ":" & txtClientPort.Text & "..."
Exit Sub
EH:
LogMessage "连接错误: " & Err.Description
End Sub
Private Sub cmdClientDisconnect_Click()
If Not m_oClient Is Nothing Then
m_oClient.Close_
LogMessage "客户端已断开连接"
End If
cmdClientConnect.Enabled = True
cmdClientDisconnect.Enabled = False
cmdClientSend.Enabled = False
End Sub
Private Sub cmdClientSend_Click()
On Error GoTo EH
If Not m_oClient Is Nothing And m_oClient.State = sckConnected Then
m_oClient.SendData txtClientData.Text
LogMessage "已发送数据: " & txtClientData.Text
End If
Exit Sub
EH:
LogMessage "发送错误: " & Err.Description
End SubTCP 服务器
TCP 服务器监听指定端口,接受多个客户端连接,并可以与每个客户端进行独立通信。

创建 TCP 服务器
vb
Private WithEvents m_oServer As cWinsock
Private Sub InitializeServer()
If m_oServer Is Nothing Then
Set m_oServer = New cWinsock
End If
m_oServer.Protocol = sckTCPProtocol
End Sub开始监听
vb
Private Sub StartListening(ByVal lPort As Long)
On Error GoTo EH
InitializeServer()
m_oServer.Listen lPort
LogMessage "服务器开始监听端口 " & lPort
Exit Sub
EH:
LogMessage "监听错误: " & Err.Description
End Sub停止监听
vb
Private Sub StopListening()
If Not m_oServer Is Nothing Then
m_oServer.Close_
LogMessage "服务器已停止监听"
End If
End Sub处理客户端连接
vb
Private Sub m_oServer_ConnectionRequest(Client As VBMANLIB.cWinsock, DisConnect As Boolean)
' 压测模式下不显示连接日志
If Not m_bStressTestMode Then
LogMessage "新客户端连接: " & Client.RemoteHostIP & ":" & Client.RemotePort & " (Tag: " & Client.Tag & ")"
End If
' 将 Tag 内容写入 listbox
lstClients.AddItem Client.Tag & " " & Client.RemoteHostIP & ":" & Client.RemotePort
End Sub压测模式
压测模式用于性能测试,在高并发场景下只统计数据而不显示详细日志:
vb
' 压测模式变量
Private m_bStressTestMode As Boolean
Private m_lMsgCount As Long ' 当前周期消息数
Private m_lBytesCount As Long ' 当前周期字节数
Private m_lTotalMsgCount As Long ' 累计消息数
Private m_lTotalBytesCount As Long ' 累计字节数
Private m_lCurrentClientCount As Long ' 当前客户端数量
Private m_dLastStatsTime As Double ' 上次统计时间
Private WithEvents tmrStats As VB.Timer
' 切换压测模式
Private Sub chkStressTest_Click()
m_bStressTestMode = (chkStressTest.Value = vbChecked)
If m_bStressTestMode Then
LogMessage "压测模式已启用 - 仅统计,不显示消息内容"
ResetStats
Else
LogMessage "压测模式已关闭 - 显示所有消息内容"
End If
End Sub
' 接收数据时(压测模式)
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Dim sResponse As String
On Error GoTo EH
If m_bStressTestMode Then
' 压测模式:只统计,不获取内容
Client.GetData sData, vbString, bytesTotal
' 累计统计
m_lMsgCount = m_lMsgCount + 1
m_lBytesCount = m_lBytesCount + bytesTotal
m_lTotalMsgCount = m_lTotalMsgCount + 1
m_lTotalBytesCount = m_lTotalBytesCount + bytesTotal
' 回显数据
sResponse = "OK"
Client.SendData sResponse
Else
' 普通模式:显示内容
Client.GetData sData
LogMessage "从客户端 " & Client.Tag & " 收到数据 (" & bytesTotal & " 字节): " & sData
sResponse = "Echo: " & sData
Client.SendData sResponse
LogMessage "已向客户端 " & Client.Tag & " 发送回显: " & sResponse
End If
Exit Sub
EH:
LogMessage "服务器接收数据错误: " & Err.Description
End Sub
' 统计定时器(每秒更新一次)
Private Sub tmrStats_Timer()
Dim dCurrentTime As Double
Dim dElapsedTime As Double
Dim lMsgPerSec As Long
Dim lBytesPerSec As Long
Dim sStats As String
If m_bStressTestMode Then
dCurrentTime = Timer
dElapsedTime = dCurrentTime - m_dLastStatsTime
If dElapsedTime > 0 Then
lMsgPerSec = CLng(m_lMsgCount / dElapsedTime)
lBytesPerSec = CLng(m_lBytesCount / dElapsedTime)
' 构建统计信息(每项一行)
sStats = vbCrLf & _
"========================================" & vbCrLf & _
Format$(Now, "hh:mm:ss") & " - [统计信息]" & vbCrLf & _
"----------------------------------------" & vbCrLf & _
"当前周期消息数: " & m_lMsgCount & vbCrLf & _
"当前周期字节数: " & m_lBytesCount & vbCrLf & _
"消息速率: " & lMsgPerSec & " msg/s" & vbCrLf & _
"数据速率: " & Format$(lBytesPerSec / 1024, "0.00") & " KB/s" & vbCrLf & _
"----------------------------------------" & vbCrLf & _
"当前客户端数量: " & m_lCurrentClientCount & vbCrLf & _
"累计消息数: " & m_lTotalMsgCount & vbCrLf & _
"累计字节数: " & Format$(m_lTotalBytesCount / 1024 / 1024, "0.00") & " MB" & vbCrLf & _
"========================================" & vbCrLf
' 直接替换文本框内容
txtLog.Text = sStats
txtLog.SelStart = Len(txtLog.Text)
' 重置当前周期统计
m_lMsgCount = 0
m_lBytesCount = 0
m_dLastStatsTime = dCurrentTime
End If
End If
End Sub接收和发送数据
vb
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
Dim sResponse As String
On Error GoTo EH
' 获取数据
Client.GetData sData
LogMessage "从客户端 " & Client.Tag & " 收到数据 (" & bytesTotal & " 字节): " & sData
' 处理数据并返回
sResponse = "Echo: " & sData
Client.SendData sResponse
LogMessage "已向客户端 " & Client.Tag & " 发送回显: " & sResponse
Exit Sub
EH:
LogMessage "服务器接收数据错误: " & Err.Description
End Sub处理客户端断开
vb
Private Sub m_oServer_CloseEvent(Client As cWinsock)
Dim i As Long
' 压测模式下不显示日志
If Not m_bStressTestMode Then
LogMessage "客户端 " & Client.RemoteHostIP & ":" & Client.RemotePort & " 已断开连接"
End If
' 用 Tag 去 listbox 遍历删除匹配项
For i = 0 To lstClients.ListCount - 1
If InStr(lstClients.List(i), Client.Tag) > 0 Then
lstClients.RemoveItem i
Exit For
End If
Next
End Sub完整示例
参考 Form1.frm 中的服务器实现:
vb
Private Sub cmdServerListen_Click()
On Error GoTo EH
If m_oServer Is Nothing Then
Set m_oServer = New cWinsock
End If
m_oServer.Protocol = sckTCPProtocol
m_oServer.Listen CLng(txtServerPort.Text)
LogMessage "服务器开始监听端口 " & txtServerPort.Text
cmdServerListen.Enabled = False
cmdServerStop.Enabled = True
Exit Sub
EH:
LogMessage "监听错误: " & Err.Description
End Sub
Private Sub m_oServer_ConnectionRequest(Client As VBMANLIB.cWinsock, DisConnect As Boolean)
LogMessage "新客户端连接: " & Client.RemoteHostIP & ":" & Client.RemotePort & " (Tag: " & Client.Tag & ")"
lstClients.AddItem Client.Tag & " - " & Client.RemoteHostIP & ":" & Client.RemotePort
End SubUDP 通信
UDP(User Datagram Protocol)是无连接的协议,适合发送少量数据或对可靠性要求不高的场景。
创建 UDP Socket
vb
Private WithEvents m_oUdp As cWinsock
Private Sub InitializeUdp()
If m_oUdp Is Nothing Then
Set m_oUdp = New cWinsock
m_oUdp.Protocol = sckUDPProtocol
End If
End Sub绑定本地端口
vb
Private Sub BindUdpPort(ByVal lPort As Long)
On Error GoTo EH
InitializeUdp()
m_oUdp.Bind lPort
LogMessage "UDP Socket 已绑定到端口 " & lPort
Exit Sub
EH:
LogMessage "UDP 绑定错误: " & Err.Description
End Sub发送 UDP 数据
vb
Private Sub SendUdpData(sHost As String, lPort As Long, sData As String)
On Error GoTo EH
With m_oUdp
.RemoteHost = sHost
.RemotePort = lPort
.SendData sData
LogMessage "UDP 已发送数据到 " & sHost & ":" & lPort & ": " & sData
End With
Exit Sub
EH:
LogMessage "UDP 发送错误: " & Err.Description
End Sub接收 UDP 数据
vb
Private Sub m_oUdp_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sData As String
On Error GoTo EH
Client.GetData sData
LogMessage "UDP 收到数据 (" & bytesTotal & " 字节) 来自 " & Client.RemoteHostIP & ":" & Client.RemotePort & ": " & sData
Exit Sub
EH:
LogMessage "UDP 接收数据错误: " & Err.Description
End Sub完整示例
参考 Form1.frm 中的 UDP 实现:
vb
Private Sub cmdUdpBind_Click()
If m_oUdp Is Nothing Then
Set m_oUdp = New cWinsock
m_oUdp.Protocol = sckUDPProtocol
End If
m_oUdp.Bind CLng(txtUdpPort.Text)
LogMessage "UDP Socket 已绑定到端口 " & txtUdpPort.Text
End Sub
Private Sub cmdUdpSend_Click()
On Error GoTo EH
With m_oUdp
.RemoteHost = txtUdpHost.Text
.RemotePort = CLng(txtUdpPort.Text)
.SendData txtUdpData.Text
LogMessage "UDP 已发送数据到 " & txtUdpHost.Text & ":" & txtUdpPort.Text & ": " & txtUdpData.Text
End With
Exit Sub
EH:
LogMessage "UDP 发送错误: " & Err.Description
End SubAPI 参考
属性
| 属性名 | 类型 | 说明 |
|---|---|---|
Protocol | Integer | 协议类型:sckTCPProtocol (0) 或 sckUDPProtocol (1) |
State | Integer | 连接状态,参见下方状态常量 |
RemoteHost | String | 远程主机地址 |
RemoteHostIP | String | 远程主机 IP 地址(只读) |
RemotePort | Long | 远程端口号 |
LocalPort | Long | 本地端口号(只读) |
Tag | Variant | 用于存储自定义数据的标签 |
方法
Connect
vb
oSocket.Connect RemoteHost, RemotePort连接到指定的服务器。
参数:
RemoteHost: 服务器地址(IP 或主机名)RemotePort: 服务器端口
Listen
vb
oSocket.Listen Port开始监听指定端口(仅 TCP 服务器模式)。
参数:
Port: 监听端口号
Bind
vb
oSocket.Bind Port绑定本地端口(仅 UDP 模式)。
参数:
Port: 绑定端口号
SendData
vb
oSocket.SendData Data发送数据到远程端点。
参数:
Data: 要发送的数据(字符串或字节数组)
GetData
vb
oSocket.GetData Data, [Type], [MaxLen]从缓冲区获取接收到的数据。
参数:
Data: 存储接收数据的变量Type: 可选,数据类型(默认为字符串)MaxLen: 可选,最大读取长度
Close_
vb
oSocket.Close_关闭连接或停止监听。
状态常量
| 常量 | 值 | 说明 |
|---|---|---|
sckClosed | 0 | 连接已关闭 |
sckOpen | 1 | Socket 已打开 |
sckListening | 2 | 正在监听 |
sckConnectionPending | 3 | 连接正在建立 |
sckResolvingHost | 4 | 正在解析主机 |
sckHostResolved | 5 | 主机已解析 |
sckConnecting | 6 | 正在连接 |
sckConnected | 7 | 已连接 |
sckClosing | 8 | 正在关闭 |
sckError | 9 | 发生错误 |
事件说明
Connect
vb
Private Sub oSocket_Connect(Client As cWinsock)客户端成功连接到服务器时触发。
参数:
Client: 触发事件的 cWinsock 对象
CloseEvent
vb
Private Sub oSocket_CloseEvent(Client As cWinsock)连接关闭时触发。
参数:
Client: 触发事件的 cWinsock 对象
ConnectionRequest
vb
Private Sub oSocket_ConnectionRequest(Client As cWinsock, DisConnect As Boolean)服务器收到新客户端连接请求时触发(仅 TCP 服务器)。
参数:
Client: 新连接的客户端对象DisConnect: 设置为 True 拒绝连接,False 接受连接
DataArrival
vb
Private Sub oSocket_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)收到数据时触发。
参数:
Client: 接收数据的客户端对象bytesTotal: 接收到的数据字节数
Error
vb
Private Sub oSocket_Error(Client As cWinsock, ByVal Number As Long, Description As String, ByVal Scode As Long)发生错误时触发。
参数:
Client: 发生错误的客户端对象Number: 错误代码Description: 错误描述Scode: 系统 Scode 错误码
高级特性
多客户端管理
服务器端会自动为每个连接创建独立的客户端对象,通过 Tag 属性可以识别不同的客户端:
vb
Private Sub m_oServer_ConnectionRequest(Client As cWinsock, DisConnect As Boolean)
' 分配唯一标识
Client.Tag = "Client_" & GetNextId()
' 存储到集合中管理
colClients.Add Client, Client.Tag
LogMessage "新客户端: " & Client.Tag
End Sub客户端认证
在 ConnectionRequest 事件中实现简单的认证:
vb
Private Sub m_oServer_ConnectionRequest(Client As cWinsock, DisConnect As Boolean)
' 检查 IP 白名单
If Not IsAllowedIP(Client.RemoteHostIP) Then
DisConnect = True
LogMessage "拒绝连接: " & Client.RemoteHostIP
Exit Sub
End If
LogMessage "接受连接: " & Client.RemoteHostIP
End Sub数据分包处理
处理大量数据时的分包传输:
vb
Private Sub m_oServer_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Static sBuffer As String
Dim sData As String
Dim lPos As Long
Client.GetData sData
sBuffer = sBuffer & sData
' 查找消息结束标记(如换行符)
Do
lPos = InStr(sBuffer, vbCrLf)
If lPos > 0 Then
ProcessMessage Client, Left(sBuffer, lPos - 1)
sBuffer = Mid(sBuffer, lPos + 2)
Else
Exit Do
End If
Loop
End Sub错误重连机制
实现自动重连:
vb
Private Sub m_oClient_CloseEvent(Client As cWinsock)
LogMessage "连接已断开,尝试重连..."
' 延迟重连
Dim i As Integer
For i = 1 To 3
If TryReconnect() Then
Exit Sub
End If
Sleep 2000
Next i
LogMessage "重连失败"
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()
If m_oClient.State <> sckConnected Then
m_oClient.Close_
LogMessage "连接超时"
tmrConnect.Enabled = False
End If
End SubQ2: 如何发送二进制数据?
A: 使用字节数组:
vb
Dim byData() As Byte
byData = StrConv("Hello", vbFromUnicode)
m_oClient.SendData byDataQ3: UDP 模式下如何区分不同的发送者?
A: 通过 RemoteHostIP 和 RemotePort 属性:
vb
Private Sub m_oUdp_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Dim sSender As String
sSender = Client.RemoteHostIP & ":" & Client.RemotePort
LogMessage "收到来自 " & sSender & " 的数据"
End SubQ4: 如何限制客户端连接数?
A: 使用计数器管理:
vb
Private lClientCount As Long
Private Sub m_oServer_ConnectionRequest(Client As cWinsock, DisConnect As Boolean)
If lClientCount >= 100 Then
DisConnect = True
LogMessage "拒绝连接:达到最大客户端数"
Exit Sub
End If
lClientCount = lClientCount + 1
LogMessage "客户端连接数: " & lClientCount
End Sub
Private Sub m_oServer_CloseEvent(Client As cWinsock)
lClientCount = lClientCount - 1
End SubQ5: 如何调试网络通信问题?
A: 使用日志记录所有关键事件:
vb
Private Sub LogMessage(sMessage As String)
txtLog.Text = txtLog.Text & Format$(Now, "hh:mm:ss") & " - " & sMessage & vbCrLf
txtLog.SelStart = Len(txtLog.Text)
Debug.Print sMessage ' 输出到立即窗口
End Sub最佳实践
- 始终检查连接状态:在发送数据前检查
State = sckConnected - 错误处理:所有网络操作都应包含错误处理
- 资源清理:窗体卸载时调用
Close_释放资源 - 日志记录:记录关键事件便于调试
- 超时处理:设置合理的连接和操作超时
- 数据校验:接收数据时进行格式和长度验证
相关资源
- 项目目录:
Winsock/ - 示例代码:
Client.frm,Form1.frm - 依赖库:
VBMAN.dll
更新日志
- v1.0 - 初始版本,包含 TCP 客户端、TCP 服务器和 UDP 示例