cWinsock 同步方法详解
📋 目录
概述
cWinsock 提供了一套完整的同步(阻塞式)网络操作方法,使开发者可以在不使用事件驱动模型的情况下进行网络通信。同步方法会在操作完成前阻塞当前线程,直到操作成功、超时或发生错误。
核心特性
- ⏱️ 超时控制 - 所有同步操作都支持超时设置
- 🔄 消息泵机制 - 通过 PeekMessage/DispatchMessage 处理消息队列,不会阻塞 UI
- 🎯 简洁 API - 函数式调用,返回 Boolean 表示成功/失败
- 🌐 全面支持 - 连接、发送、接收、事件等待全覆盖
- 💻 编码灵活 - 支持多种文本编码(ACP/GBK、UTF-8、Unicode)
适用场景
- 简单的客户端应用(如 HTTP 客户端)
- 需要顺序执行的网络操作
- 不需要复杂事件处理的场景
- 快速原型开发
同步方法列表
| 方法名 | 返回类型 | 说明 |
|---|---|---|
SyncConnect | Boolean | 同步连接到远程服务器 |
SyncSendText | Boolean | 同步发送字符串 |
SyncSendArray | Boolean | 同步发送字节数组 |
SyncSend | Boolean | 同步发送缓冲区数据 |
SyncReceiveText | String | 同步接收字符串 |
SyncReceiveArray | Boolean | 同步接收到字节数组 |
SyncReceive | Boolean | 同步接收到缓冲区 |
SyncWaitForEvent | Boolean | 等待指定套接字事件 |
SyncCancelWait | Sub | 取消等待操作 |
事件掩码枚举
WinSocketEventMaskEnum 用于指定 SyncWaitForEvent 要等待的事件类型。
枚举值
| 枚举名 | 值 | 说明 |
|---|---|---|
wskSfdRead | 2^0 | 可读事件 |
wskSfdWrite | 2^1 | 可写事件 |
wskSfdOob | 2^2 | 带外数据 |
wskSfdAccept | 2^3 | 接受连接 |
wskSfdConnect | 2^4 | 连接完成 |
wskSfdClose | 2^5 | 连接关闭 |
wskSfdAll | 2^6 - 1 | 所有事件(默认) |
[_wskSfdResolve] | 2^15 | 内部:域名解析 |
[_wskSfdForceRead] | 2^14 | 内部:强制读取 |
使用示例
vb
' 等待可读事件
If ws.SyncWaitForEvent(5000, wskSfdRead) Then
Debug.Print "套接字可读"
End If
' 等待可写或可读事件
If ws.SyncWaitForEvent(5000, wskSfdRead Or wskSfdWrite) Then
Debug.Print "套接字就绪"
End If
' 等待任何事件
If ws.SyncWaitForEvent(5000, wskSfdAll) Then
Debug.Print "事件触发"
End If方法详解
SyncConnect - 同步连接
说明
同步连接到指定的远程服务器,带有超时控制。连接成功后返回 True,超时或失败返回 False。
语法
vb
Public Function SyncConnect(HostAddress As String, ByVal HostPort As Long, Optional ByVal TimeOut As Long) As Boolean参数
| 参数 | 类型 | 说明 |
|---|---|---|
HostAddress | String | 远程主机名或 IP 地址 |
HostPort | Long | 远程端口号 |
TimeOut | Long(可选) | 超时时间(毫秒),默认使用底层默认值 |
返回值
True- 连接成功False- 连接失败或超时
使用示例
vb
Private Sub TestSyncConnect()
Dim ws As New cWinsock
Dim bResult As Boolean
' 连接到 example.com 的 80 端口,超时 5 秒
bResult = ws.SyncConnect("example.com", 80, 5000)
If bResult Then
Debug.Print "连接成功!"
Debug.Print "远程 IP: " & ws.RemoteHostIP
Debug.Print "本地 IP: " & ws.LocalIP
Debug.Print "本地端口: " & ws.LocalPort
Else
Debug.Print "连接失败或超时"
End If
ws.Close_
End Sub错误处理
vb
Private Sub TestConnectWithError()
Dim ws As New cWinsock
On Error GoTo EH
If ws.SyncConnect("invalid-host-name-12345.com", 80, 3000) Then
Debug.Print "连接成功"
Else
Debug.Print "连接失败"
End If
Exit Sub
EH:
Debug.Print "连接错误: " & Err.Description & " (错误号: " & Err.Number & ")"
ws.Close_
End SubSyncSendText - 同步发送文本
说明
同步发送字符串数据,带有超时控制。
语法
vb
Public Function SyncSendText( _
Text As String, _
Optional ByVal TimeOut As Long, _
Optional HostAddress As String, _
Optional ByVal HostPort As Long, _
Optional ByVal CodePage As EnumScpCodePage = wcpUtf8) As Boolean参数
| 参数 | 类型 | 说明 |
|---|---|---|
Text | String | 要发送的文本 |
TimeOut | Long(可选) | 超时时间(毫秒) |
HostAddress | String(可选) | 目标主机地址(UDP 服务器模式使用) |
HostPort | Long(可选) | 目标端口(UDP 服务器模式使用) |
CodePage | EnumScpCodePage(可选) | 文本编码,默认 wcpUtf8 |
返回值
True- 发送成功False- 发送失败或超时
使用示例
vb
Private Sub TestSyncSendText()
Dim ws As New cWinsock
' 连接
If ws.SyncConnect("example.com", 80, 5000) Then
' 发送 HTTP 请求
Dim sRequest As String
sRequest = "GET / HTTP/1.1" & vbCrLf & _
"Host: example.com" & vbCrLf & vbCrLf
If ws.SyncSendText(sRequest, 5000, , , wcpUtf8) Then
Debug.Print "发送成功"
Else
Debug.Print "发送失败"
End If
End If
ws.Close_
End Sub使用不同编码
vb
' 使用 GBK 编码(默认)
ws.SyncSendText "中文测试", 5000, , , wcpAcp
' 使用 UTF-8 编码(推荐)
ws.SyncSendText "中文测试", 5000, , , wcpUtf8
' 使用 Unicode(不转换)
ws.SyncSendText "中文测试", 5000, , , wcpUnicodeSyncSendArray - 同步发送字节数组
说明
同步发送字节数组数据,带有超时控制。
语法
vb
Public Function SyncSendArray( _
Buffer() As Byte, _
Optional ByVal TimeOut As Long, _
Optional HostAddress As String, _
Optional ByVal HostPort As Long, _
Optional ByVal Flags As Long = 0) As Boolean参数
| 参数 | 类型 | 说明 |
|---|---|---|
Buffer | Byte() | 要发送的字节数组 |
TimeOut | Long(可选) | 超时时间(毫秒) |
HostAddress | String(可选) | 目标主机地址 |
HostPort | Long(可选) | 目标端口 |
Flags | Long(可选) | 发送标志位 |
返回值
True- 发送成功False- 发送失败或超时
使用示例
vb
Private Sub TestSyncSendArray()
Dim ws As New cWinsock
Dim baData() As Byte
' 准备数据
baData = StrConv("Hello World", vbFromUnicode)
' 连接并发送
If ws.SyncConnect("127.0.0.1", 8080, 5000) Then
If ws.SyncSendArray(baData, 5000) Then
Debug.Print "字节数组发送成功"
End If
End If
ws.Close_
End SubSyncSend - 同步发送缓冲区
说明
同步从指定缓冲区指针发送数据,用于高性能场景。
语法
vb
Public Function SyncSend( _
ByVal BufPtr As Long, _
ByVal BufLen As Long, _
Optional ByVal TimeOut As Long, _
Optional HostAddress As String, _
Optional ByVal HostPort As Long, _
Optional ByVal Flags As Long = 0) As Boolean参数
| 参数 | 类型 | 说明 |
|---|---|---|
BufPtr | Long | 缓冲区指针 |
BufLen | Long | 缓冲区长度 |
TimeOut | Long(可选) | 超时时间(毫秒) |
HostAddress | String(可选) | 目标主机地址 |
HostPort | Long(可选) | 目标端口 |
Flags | Long(可选) | 发送标志位 |
返回值
True- 发送成功False- 发送失败或超时
使用示例
vb
' 注意:此方法需要内存指针操作,通常用于高级场景
Private Sub TestSyncSend()
Dim ws As New cWinsock
Dim sData As String
Dim lPtr As Long
sData = "Hello World"
' 获取字符串指针(使用 StrPtr)
lPtr = StrPtr(sData)
If ws.SyncConnect("127.0.0.1", 8080, 5000) Then
If ws.SyncSend(lPtr, LenB(sData), 5000) Then
Debug.Print "发送成功"
End If
End If
ws.Close_
End SubSyncReceiveText - 同步接收文本
说明
同步接收文本数据,带有超时控制。可以指定接收的最小字节数。
语法
vb
Public Function SyncReceiveText( _
Optional ByVal NeedLen As Long = 1, _
Optional ByVal TimeOut As Long, _
Optional HostAddress As String, _
Optional HostPort As Long, _
Optional ByVal CodePage As EnumScpCodePage = wcpUtf8) As String参数
| 参数 | 类型 | 说明 |
|---|---|---|
NeedLen | Long(可选) | 最小接收字节数,默认 1 |
TimeOut | Long(可选) | 超时时间(毫秒) |
HostAddress | String(可选) | 源主机地址(UDP 模式) |
HostPort | Long(可选) | 源端口(UDP 模式) |
CodePage | EnumScpCodePage(可选) | 文本编码,默认 wcpUtf8 |
返回值
- 成功:返回接收到的文本
- 失败:返回空字符串
使用示例
vb
Private Sub TestSyncReceiveText()
Dim ws As New cWinsock
Dim sResponse As String
' 连接
If ws.SyncConnect("example.com", 80, 5000) Then
' 发送请求
Dim sRequest As String
sRequest = "GET / HTTP/1.1" & vbCrLf & _
"Host: example.com" & vbCrLf & vbCrLf
If ws.SyncSendText(sRequest, 5000, , , wcpUtf8) Then
' 接收响应(至少 100 字节,超时 5 秒)
sResponse = ws.SyncReceiveText(100, 5000, , , wcpUtf8)
If Len(sResponse) > 0 Then
Debug.Print "收到响应:"
Debug.Print sResponse
Debug.Print "长度: " & Len(sResponse) & " 字符"
Else
Debug.Print "接收失败或超时"
End If
End If
End If
ws.Close_
End Sub读取固定长度
vb
' 读取前 100 字节
Dim sHeader As String
sHeader = ws.SyncReceiveText(100, 3000, , , wcpUtf8)
Debug.Print "头部: " & sHeaderSyncReceiveArray - 同步接收字节数组
说明
同步接收字节数组数据,带有超时控制。
语法
vb
Public Function SyncReceiveArray( _
Buffer() As Byte, _
Optional ByVal NeedLen As Long, _
Optional ByVal TimeOut As Long, _
Optional HostAddress As String, _
Optional ByVal HostPort As Long, _
Optional ByVal Flags As Long = 0) As Boolean参数
| 参数 | 类型 | 说明 |
|---|---|---|
Buffer | Byte() | 用于接收数据的字节数组 |
NeedLen | Long(可选) | 最小接收字节数 |
TimeOut | Long(可选) | 超时时间(毫秒) |
HostAddress | String(可选) | 源主机地址 |
HostPort | Long(可选) | 源端口 |
Flags | Long(可选) | 接收标志位 |
返回值
True- 接收成功False- 接收失败或超时
使用示例
vb
Private Sub TestSyncReceiveArray()
Dim ws As New cWinsock
Dim baBuffer() As Byte
' 连接
If ws.SyncConnect("127.0.0.1", 8080, 5000) Then
' 发送请求
If ws.SyncSendText("GET_DATA", 5000, , , wcpUtf8) Then
' 接收响应(最大 8192 字节)
ReDim baBuffer(0 To 8191) As Byte
If ws.SyncReceiveArray(baBuffer, 1, 5000) Then
' 获取实际接收长度
Dim lReceived As Long
lReceived = UBound(baBuffer) + 1
Debug.Print "收到 " & lReceived & " 字节"
Else
Debug.Print "接收失败或超时"
End If
End If
End If
ws.Close_
End SubSyncReceive - 同步接收到缓冲区
说明
同步从套接字接收数据到指定缓冲区指针,用于高性能场景。
语法
vb
Public Function SyncReceive( _
ByVal BufPtr As Long, _
ByVal BufLen As Long, _
ByRef Received As Long, _
Optional ByVal TimeOut As Long, _
Optional HostAddress As String, _
Optional ByVal HostPort As Long, _
Optional ByVal Flags As Long = 0) As Boolean参数
| 参数 | 类型 | 说明 |
|---|---|---|
BufPtr | Long | 缓冲区指针 |
BufLen | Long | 缓冲区长度 |
Received | Long(传址) | 实际接收的字节数 |
TimeOut | Long(可选) | 超时时间(毫秒) |
HostAddress | String(可选) | 源主机地址 |
HostPort | Long(可选) | 源端口 |
Flags | Long(可选) | 接收标志位 |
返回值
True- 接收成功,Received包含实际接收字节数False- 接收失败或超时
使用示例
vb
Private Sub TestSyncReceive()
Dim ws As New cWinsock
Dim baBuffer() As Byte
Dim lReceived As Long
' 准备缓冲区
ReDim baBuffer(0 To 8191) As Byte
' 连接
If ws.SyncConnect("127.0.0.1", 8080, 5000) Then
' 发送请求
If ws.SyncSendText("GET_DATA", 5000, , , wcpUtf8) Then
' 接收响应
If ws.SyncReceive(VarPtr(baBuffer(0)), 8192, lReceived, 5000) Then
Debug.Print "实际收到: " & lReceived & " 字节"
' 只使用实际接收的部分
If lReceived > 0 Then
ReDim Preserve baBuffer(0 To lReceived - 1)
End If
Else
Debug.Print "接收失败或超时"
End If
End If
End If
ws.Close_
End SubSyncWaitForEvent - 等待事件
说明
等待指定的套接字事件发生,带有超时控制。可用于轮询特定事件或实现自定义协议。
语法
vb
Public Function SyncWaitForEvent( _
ByVal TimeOut As Long, _
Optional ByVal EventMask As WinSocketEventMaskEnum = wskSfdAll) As Boolean参数
| 参数 | 类型 | 说明 |
|---|---|---|
TimeOut | Long | 超时时间(毫秒) |
EventMask | WinSocketEventMaskEnum(可选) | 事件掩码,默认 wskSfdAll |
返回值
True- 指定事件发生False- 超时或错误
使用示例
vb
Private Sub TestWaitForEvent()
Dim ws As New cWinsock
' 连接
If ws.SyncConnect("example.com", 80, 5000) Then
' 等待可写事件(表示套接字准备好发送数据)
If ws.SyncWaitForEvent(5000, wskSfdWrite) Then
Debug.Print "套接字可写,可以发送数据"
' 发送数据
ws.SyncSendText "Hello", 5000, , , wcpUtf8
End If
' 等待可读事件(表示有数据可读)
If ws.SyncWaitForEvent(5000, wskSfdRead) Then
Debug.Print "套接字可读,可以接收数据"
Dim sData As String
sData = ws.SyncReceiveText(1, 5000, , , wcpUtf8)
Debug.Print "收到: " & sData
End If
End If
ws.Close_
End Sub等待多个事件
vb
' 等待可读或可写事件
Dim lMask As Long
lMask = wskSfdRead Or wskSfdWrite
If ws.SyncWaitForEvent(5000, lMask) Then
' 检查 BytesReceived 来判断具体是哪个事件
If ws.BytesReceived > 0 Then
Debug.Print "有数据可读"
Else
Debug.Print "套接字可写"
End If
End IfSyncCancelWait - 取消等待
说明
取消当前正在进行的同步等待操作(如 SyncWaitForEvent、SyncReceiveText 等)。
语法
vb
Public Sub SyncCancelWait()使用场景
- 在窗体关闭时取消正在进行的网络操作
- 在用户取消操作时中断等待
- 多线程场景中通知停止
使用示例
vb
Private WithEvents m_oWinsock As cWinsock
Private m_bCancelled As Boolean
Private Sub cmdStart_Click()
Set m_oWinsock = New cWinsock
If m_oWinsock.SyncConnect("example.com", 80, 5000) Then
' 开始等待数据
Dim sData As String
m_bCancelled = False
Do
' 检查是否取消
If m_bCancelled Then
Debug.Print "用户取消操作"
m_oWinsock.SyncCancelWait
Exit Do
End If
' 接收数据
sData = m_oWinsock.SyncReceiveText(1, 1000, , , wcpUtf8)
If Len(sData) > 0 Then
Debug.Print "收到: " & sData
Else
Debug.Print "超时,继续等待..."
End If
DoEvents ' 允许 UI 响应
Loop Until False
End If
m_oWinsock.Close_
End Sub
Private Sub cmdCancel_Click()
m_bCancelled = True
End Sub
Private Sub Form_Unload(Cancel As Integer)
' 窗体关闭时取消等待
If Not m_oWinsock Is Nothing Then
m_oWinsock.SyncCancelWait
m_oWinsock.Close_
End If
End Sub使用场景
场景 1:HTTP 客户端
vb
Private Function HttpGet(ByVal sUrl As String, ByVal sPath As String) As String
Dim ws As New cWinsock
Dim sHost As String
Dim nPort As Long
Dim sRequest As String
Dim sResponse As String
' 解析 URL(简化版)
sHost = ExtractHost(sUrl)
nPort = ExtractPort(sUrl, 80)
' 连接
If Not ws.SyncConnect(sHost, nPort, 5000) Then
HttpGet = "连接失败"
Exit Function
End If
' 构造请求
sRequest = "GET " & sPath & " HTTP/1.1" & vbCrLf & _
"Host: " & sHost & vbCrLf & _
"Connection: close" & vbCrLf & vbCrLf
' 发送请求
If Not ws.SyncSendText(sRequest, 5000, , , wcpUtf8) Then
HttpGet = "发送失败"
ws.Close_
Exit Function
End If
' 接收响应
sResponse = ws.SyncReceiveText(1, 5000, , , wcpUtf8)
ws.Close_
HttpGet = sResponse
End Function
' 使用
Dim sHtml As String
sHtml = HttpGet("http://example.com", "/")
Debug.Print sHtml场景 2:Echo 客户端
vb
Private Sub EchoClient()
Dim ws As New cWinsock
' 连接到 Echo 服务器
If ws.SyncConnect("127.0.0.1", 7, 5000) Then
Debug.Print "已连接到 Echo 服务器"
' 发送消息
Dim sMessage As String
sMessage = "Hello, Echo Server!"
If ws.SyncSendText(sMessage, 5000, , , wcpUtf8) Then
Debug.Print "发送: " & sMessage
' 接收回显
Dim sReply As String
sReply = ws.SyncReceiveText(Len(sMessage), 5000, , , wcpUtf8)
Debug.Print "接收: " & sReply
End If
End If
ws.Close_
End Sub场景 3:文件上传(简化版)
vb
Private Sub UploadFile(ByVal sFilePath As String, ByVal sServer As String, ByVal nPort As Long)
Dim ws As New cWinsock
Dim baBuffer() As Byte
Dim nFileNum As Integer
Dim lFileSize As Long
Dim lOffset As Long
Dim lChunkSize As Long
' 连接服务器
If Not ws.SyncConnect(sServer, nPort, 5000) Then
Debug.Print "连接失败"
Exit Sub
End If
' 打开文件
nFileNum = FreeFile
Open sFilePath For Binary As #nFileNum
lFileSize = LOF(nFileNum)
' 发送文件头
Dim sHeader As String
sHeader = "UPLOAD:" & CStr(lFileSize) & vbCrLf
ws.SyncSendText sHeader, 5000, , , wcpUtf8
' 分块发送
lChunkSize = 8192 ' 8KB 每块
lOffset = 1
Do While lOffset <= lFileSize
ReDim baBuffer(0 To lChunkSize - 1) As Byte
Get #nFileNum, lOffset, baBuffer
' 调整最后一块的大小
If lOffset + lChunkSize > lFileSize + 1 Then
ReDim Preserve baBuffer(0 To lFileSize + 1 - lOffset) As Byte
End If
' 发送块
If Not ws.SyncSendArray(baBuffer, 5000) Then
Debug.Print "发送失败于偏移: " & lOffset
Exit Do
End If
lOffset = lOffset + lChunkSize
' 更新进度
Debug.Print "已发送: " & Format((lOffset - 1) / lFileSize * 100, "0.00") & "%"
DoEvents
Loop
Close #nFileNum
ws.Close_
Debug.Print "上传完成"
End Sub异步 vs 同步
异步事件驱动模式
优点:
- ✅ 不会阻塞 UI 线程
- ✅ 适合高并发场景
- ✅ 响应及时
- ✅ 可以处理多个客户端
缺点:
- ❌ 代码分散在多个事件中
- ❌ 逻辑流程不直观
- ❌ 需要维护状态变量
vb
' 异步模式
Private WithEvents ws As cWinsock
Private m_bWaiting As Boolean
Private m_sResponse As String
Private Sub cmdConnect_Click()
Set ws = New cWinsock
ws.Connect "example.com", 80
m_bWaiting = True
Do While m_bWaiting
DoEvents
Loop
End Sub
Private Sub ws_Connect(Client As cWinsock)
Client.SendData "GET / HTTP/1.1" & vbCrLf
End Sub
Private Sub ws_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Client.GetData m_sResponse
m_bWaiting = False
End Sub同步阻塞模式
优点:
- ✅ 代码线性,逻辑清晰
- ✅ 易于理解和调试
- ✅ 适合简单顺序操作
- ✅ 无需维护状态变量
缺点:
- ❌ 会阻塞当前执行流
- ❌ 不适合高并发
- ❌ 需要手动调用 DoEvents 保持 UI 响应
vb
' 同步模式
Private Sub cmdConnect_Click()
Dim ws As New cWinsock
' 连接
If ws.SyncConnect("example.com", 80, 5000) Then
' 发送
If ws.SyncSendText("GET / HTTP/1.1" & vbCrLf, 5000, , , wcpUtf8) Then
' 接收
Dim sResponse As String
sResponse = ws.SyncReceiveText(1, 5000, , , wcpUtf8)
Debug.Print sResponse
End If
End If
ws.Close_
End Sub选择建议
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| 简单 HTTP 客户端 | 同步 | 顺序操作,逻辑简单 |
| TCP 服务器 | 异步 | 需要处理多个客户端 |
| 高并发应用 | 异步 | 避免阻塞 |
| 快速原型 | 同步 | 开发速度快 |
| 文件传输 | 同步 | 简单的请求-响应 |
| 实时通信 | 异步 | 及时响应 |
注意事项
⚠️ 重要注意事项
消息泵机制
- 同步方法内部使用
PeekMessage/DispatchMessage处理消息队列 - 不会阻塞 UI 消息循环,窗体仍然可以响应
- 无需手动调用
DoEvents
- 同步方法内部使用
超时设置
- 建议所有同步操作都设置合理的超时时间
- 超时时间根据网络环境调整(建议 3-30 秒)
- 超时后会自动返回失败状态
错误处理
- 所有同步方法应该配合
On Error使用 - 检查返回值判断操作是否成功
- 使用
GetErrorDescription获取错误描述
- 所有同步方法应该配合
资源清理
- 务必在操作完成后调用
Close_ - 在窗体卸载时取消正在进行的等待操作
- 使用
SyncCancelWait中断长时间等待
- 务必在操作完成后调用
编码问题
- 默认编码为
wcpUtf8 - 确保发送和接收使用相同的编码
- 与其他系统通信时明确编码协议
- 默认编码为
状态检查
- 调用同步方法前确保 socket 已连接
- 使用
State属性检查连接状态 - 使用
BytesReceived检查可用数据
⚠️ 性能注意事项
避免频繁的小数据发送
- 合并小数据块一起发送
- 使用缓冲区批量处理
合理设置超时
- 过短的超时可能导致误判
- 过长的超时会降低响应速度
内存管理
- 及时释放大字节数组
- 避免在循环中重复分配内存
⚠️ 线程安全
- 同步方法不支持多线程场景
- 所有操作应在主线程执行
- 不要在后台线程中调用同步方法
完整示例
完整的 HTTP 客户端示例
vb
' Form1.frm
Option Explicit
Private WithEvents m_oWinsock As cWinsock
Private m_bCancelled As Boolean
Private Sub cmdGet_Click()
Dim sUrl As String
Dim sHost As String
Dim nPort As Long
Dim sPath As String
Dim sRequest As String
Dim sResponse As String
' 获取 URL
sUrl = txtUrl.Text
' 解析 URL
ParseUrl sUrl, sHost, nPort, sPath
If Len(sHost) = 0 Then
MsgBox "无效的 URL", vbExclamation
Exit Sub
End If
' 创建 socket
Set m_oWinsock = New cWinsock
m_bCancelled = False
' 禁用按钮
cmdGet.Enabled = False
cmdCancel.Enabled = True
' 连接
If Not m_oWinsock.SyncConnect(sHost, nPort, 5000) Then
MsgBox "连接失败: " & m_oWinsock.GetErrorDescription(Err.LastDllError), vbExclamation
ResetUI
Exit Sub
End If
Debug.Print "已连接到 " & sHost & ":" & nPort
' 检查取消
If m_bCancelled Then
ResetUI
Exit Sub
End If
' 构造请求
sRequest = "GET " & sPath & " HTTP/1.1" & vbCrLf & _
"Host: " & sHost & vbCrLf & _
"User-Agent: cWinsock/1.0" & vbCrLf & _
"Connection: close" & vbCrLf & vbCrLf
' 发送请求
If Not m_oWinsock.SyncSendText(sRequest, 5000, , , wcpUtf8) Then
MsgBox "发送失败", vbExclamation
ResetUI
Exit Sub
End If
Debug.Print "已发送请求"
' 检查取消
If m_bCancelled Then
ResetUI
Exit Sub
End If
' 接收响应
sResponse = m_oWinsock.SyncReceiveText(1, 10000, , , wcpUtf8)
If Len(sResponse) > 0 Then
Debug.Print "收到响应,长度: " & Len(sResponse)
txtResponse.Text = sResponse
Else
MsgBox "接收超时或失败", vbExclamation
End If
' 清理
ResetUI
End Sub
Private Sub cmdCancel_Click()
m_bCancelled = True
If Not m_oWinsock Is Nothing Then
m_oWinsock.SyncCancelWait
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
If Not m_oWinsock Is Nothing Then
m_oWinsock.SyncCancelWait
m_oWinsock.Close_
Set m_oWinsock = Nothing
End If
End Sub
Private Sub ResetUI()
If Not m_oWinsock Is Nothing Then
m_oWinsock.Close_
Set m_oWinsock = Nothing
End If
cmdGet.Enabled = True
cmdCancel.Enabled = False
End Sub
Private Sub ParseUrl(ByVal sUrl As String, ByRef sHost As String, ByRef nPort As Long, ByRef sPath As String)
Dim sTemp As String
Dim nPos As Long
Dim nPortPos As Long
Dim nPathPos As Long
' 移除协议前缀
If InStr(1, sUrl, "://") > 0 Then
sUrl = Mid$(sUrl, InStr(sUrl, "://") + 3)
End If
' 查找路径开始位置
nPathPos = InStr(1, sUrl, "/")
If nPathPos = 0 Then
nPathPos = Len(sUrl) + 1
End If
' 提取主机和端口
sTemp = Left$(sUrl, nPathPos - 1)
' 查找端口
nPortPos = InStr(1, sTemp, ":")
If nPortPos > 0 Then
sHost = Left$(sTemp, nPortPos - 1)
nPort = Val(Mid$(sTemp, nPortPos + 1))
Else
sHost = sTemp
nPort = 80
End If
' 提取路径
sPath = Mid$(sUrl, nPathPos)
If Len(sPath) = 0 Then
sPath = "/"
End If
End Sub简单的聊天客户端示例
vb
Private WithEvents m_oWinsock As cWinsock
Private Sub cmdConnect_Click()
Set m_oWinsock = New cWinsock
If m_oWinsock.SyncConnect(txtServer.Text, Val(txtPort.Text), 5000) Then
Debug.Print "已连接到服务器"
txtSend.Enabled = True
cmdConnect.Enabled = False
cmdDisconnect.Enabled = True
Else
MsgBox "连接失败", vbExclamation
End If
End Sub
Private Sub cmdDisconnect_Click()
If Not m_oWinsock Is Nothing Then
m_oWinsock.SyncCancelWait
m_oWinsock.Close_
Set m_oWinsock = Nothing
End If
txtSend.Enabled = False
cmdConnect.Enabled = True
cmdDisconnect.Enabled = False
End Sub
Private Sub cmdSend_Click()
If m_oWinsock Is Nothing Then Exit Sub
Dim sMessage As String
sMessage = "[" & txtNick.Text & "]: " & txtSend.Text
If m_oWinsock.SyncSendText(sMessage, 5000, , , wcpUtf8) Then
txtReceive.Text = txtReceive.Text & sMessage & vbCrLf
txtSend.Text = ""
Else
MsgBox "发送失败", vbExclamation
End If
End Sub
Private Sub tmrReceive_Timer()
If m_oWinsock Is Nothing Or m_oWinsock.State <> sckConnected Then Exit Sub
' 检查是否有数据
If m_oWinsock.BytesReceived > 0 Then
Dim sData As String
sData = m_oWinsock.SyncReceiveText(1, 100, , , wcpUtf8)
If Len(sData) > 0 Then
txtReceive.Text = txtReceive.Text & sData & vbCrLf
txtReceive.SelStart = Len(txtReceive.Text)
End If
End If
End Sub总结
cWinsock 的同步方法提供了一种简单、直观的网络编程方式,特别适合:
- 🎯 简单客户端应用 - HTTP、Echo、聊天等
- 📚 学习网络编程 - 线性代码易于理解
- ⚡ 快速原型开发 - 快速验证想法
- 🔄 顺序操作 - 需要按步骤执行的任务
对于更复杂的服务器或高并发场景,建议使用异步事件驱动模式。
最后更新: 2026-01-26