Skip to content

cWinsock 同步方法详解

📋 目录


概述

cWinsock 提供了一套完整的同步(阻塞式)网络操作方法,使开发者可以在不使用事件驱动模型的情况下进行网络通信。同步方法会在操作完成前阻塞当前线程,直到操作成功、超时或发生错误。

核心特性

  • ⏱️ 超时控制 - 所有同步操作都支持超时设置
  • 🔄 消息泵机制 - 通过 PeekMessage/DispatchMessage 处理消息队列,不会阻塞 UI
  • 🎯 简洁 API - 函数式调用,返回 Boolean 表示成功/失败
  • 🌐 全面支持 - 连接、发送、接收、事件等待全覆盖
  • 💻 编码灵活 - 支持多种文本编码(ACP/GBK、UTF-8、Unicode)

适用场景

  • 简单的客户端应用(如 HTTP 客户端)
  • 需要顺序执行的网络操作
  • 不需要复杂事件处理的场景
  • 快速原型开发

同步方法列表

方法名返回类型说明
SyncConnectBoolean同步连接到远程服务器
SyncSendTextBoolean同步发送字符串
SyncSendArrayBoolean同步发送字节数组
SyncSendBoolean同步发送缓冲区数据
SyncReceiveTextString同步接收字符串
SyncReceiveArrayBoolean同步接收到字节数组
SyncReceiveBoolean同步接收到缓冲区
SyncWaitForEventBoolean等待指定套接字事件
SyncCancelWaitSub取消等待操作

事件掩码枚举

WinSocketEventMaskEnum 用于指定 SyncWaitForEvent 要等待的事件类型。

枚举值

枚举名说明
wskSfdRead2^0可读事件
wskSfdWrite2^1可写事件
wskSfdOob2^2带外数据
wskSfdAccept2^3接受连接
wskSfdConnect2^4连接完成
wskSfdClose2^5连接关闭
wskSfdAll2^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

参数

参数类型说明
HostAddressString远程主机名或 IP 地址
HostPortLong远程端口号
TimeOutLong(可选)超时时间(毫秒),默认使用底层默认值

返回值

  • 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 Sub

SyncSendText - 同步发送文本

说明

同步发送字符串数据,带有超时控制。

语法

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

参数

参数类型说明
TextString要发送的文本
TimeOutLong(可选)超时时间(毫秒)
HostAddressString(可选)目标主机地址(UDP 服务器模式使用)
HostPortLong(可选)目标端口(UDP 服务器模式使用)
CodePageEnumScpCodePage(可选)文本编码,默认 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, , , wcpUnicode

SyncSendArray - 同步发送字节数组

说明

同步发送字节数组数据,带有超时控制。

语法

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

参数

参数类型说明
BufferByte()要发送的字节数组
TimeOutLong(可选)超时时间(毫秒)
HostAddressString(可选)目标主机地址
HostPortLong(可选)目标端口
FlagsLong(可选)发送标志位

返回值

  • 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 Sub

SyncSend - 同步发送缓冲区

说明

同步从指定缓冲区指针发送数据,用于高性能场景。

语法

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

参数

参数类型说明
BufPtrLong缓冲区指针
BufLenLong缓冲区长度
TimeOutLong(可选)超时时间(毫秒)
HostAddressString(可选)目标主机地址
HostPortLong(可选)目标端口
FlagsLong(可选)发送标志位

返回值

  • 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 Sub

SyncReceiveText - 同步接收文本

说明

同步接收文本数据,带有超时控制。可以指定接收的最小字节数。

语法

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

参数

参数类型说明
NeedLenLong(可选)最小接收字节数,默认 1
TimeOutLong(可选)超时时间(毫秒)
HostAddressString(可选)源主机地址(UDP 模式)
HostPortLong(可选)源端口(UDP 模式)
CodePageEnumScpCodePage(可选)文本编码,默认 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 "头部: " & sHeader

SyncReceiveArray - 同步接收字节数组

说明

同步接收字节数组数据,带有超时控制。

语法

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

参数

参数类型说明
BufferByte()用于接收数据的字节数组
NeedLenLong(可选)最小接收字节数
TimeOutLong(可选)超时时间(毫秒)
HostAddressString(可选)源主机地址
HostPortLong(可选)源端口
FlagsLong(可选)接收标志位

返回值

  • 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 Sub

SyncReceive - 同步接收到缓冲区

说明

同步从套接字接收数据到指定缓冲区指针,用于高性能场景。

语法

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

参数

参数类型说明
BufPtrLong缓冲区指针
BufLenLong缓冲区长度
ReceivedLong(传址)实际接收的字节数
TimeOutLong(可选)超时时间(毫秒)
HostAddressString(可选)源主机地址
HostPortLong(可选)源端口
FlagsLong(可选)接收标志位

返回值

  • 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 Sub

SyncWaitForEvent - 等待事件

说明

等待指定的套接字事件发生,带有超时控制。可用于轮询特定事件或实现自定义协议。

语法

vb
Public Function SyncWaitForEvent( _
    ByVal TimeOut As Long, _
    Optional ByVal EventMask As WinSocketEventMaskEnum = wskSfdAll) As Boolean

参数

参数类型说明
TimeOutLong超时时间(毫秒)
EventMaskWinSocketEventMaskEnum(可选)事件掩码,默认 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 If

SyncCancelWait - 取消等待

说明

取消当前正在进行的同步等待操作(如 SyncWaitForEventSyncReceiveText 等)。

语法

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 服务器异步需要处理多个客户端
高并发应用异步避免阻塞
快速原型同步开发速度快
文件传输同步简单的请求-响应
实时通信异步及时响应

注意事项

⚠️ 重要注意事项

  1. 消息泵机制

    • 同步方法内部使用 PeekMessage/DispatchMessage 处理消息队列
    • 不会阻塞 UI 消息循环,窗体仍然可以响应
    • 无需手动调用 DoEvents
  2. 超时设置

    • 建议所有同步操作都设置合理的超时时间
    • 超时时间根据网络环境调整(建议 3-30 秒)
    • 超时后会自动返回失败状态
  3. 错误处理

    • 所有同步方法应该配合 On Error 使用
    • 检查返回值判断操作是否成功
    • 使用 GetErrorDescription 获取错误描述
  4. 资源清理

    • 务必在操作完成后调用 Close_
    • 在窗体卸载时取消正在进行的等待操作
    • 使用 SyncCancelWait 中断长时间等待
  5. 编码问题

    • 默认编码为 wcpUtf8
    • 确保发送和接收使用相同的编码
    • 与其他系统通信时明确编码协议
  6. 状态检查

    • 调用同步方法前确保 socket 已连接
    • 使用 State 属性检查连接状态
    • 使用 BytesReceived 检查可用数据

⚠️ 性能注意事项

  1. 避免频繁的小数据发送

    • 合并小数据块一起发送
    • 使用缓冲区批量处理
  2. 合理设置超时

    • 过短的超时可能导致误判
    • 过长的超时会降低响应速度
  3. 内存管理

    • 及时释放大字节数组
    • 避免在循环中重复分配内存

⚠️ 线程安全

  • 同步方法支持多线程场景
  • 所有操作应在主线程执行
  • 不要在后台线程中调用同步方法

完整示例

完整的 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

VB6及其LOGO版权为微软公司所有