You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.net Socket响应字符串被截断问题求助

VB.NET Socket接收数据截断问题

我的VB.NET代码可正常连接Socket服务器、完成认证与订阅,但服务器响应字符串会在243字符处被截断,导致JSON解析器因字符串不完整抛出错误。逻辑完全一致的C#版本能正常获取完整数据,怀疑和缓冲区大小有关,但不确定。

相关代码

Public Sub Run()
    Try
        Console.WriteLine("Connecting...")
        Dim client As New TcpClient("xxxxxxxx", xxxxx)
        client.Client.ReceiveBufferSize = 64 * 1024 * 1024
        client.ReceiveBufferSize = 64 * 1024 * 1024

        Dim ns As NetworkStream = client.GetStream

        SendMessage(ns, "{""r"":""authenticate"",""a"":{""key"":""xxxxxxxxxx""}}")
        SendMessage(ns, "{""r"":""subscribe_events"",""a"":{ ""sport_id"":"""", ""changes_after"":""2022-11-11T00:00:00Z""}}")
        ReceiveAsync(client)
        Console.WriteLine("Connected...")
        receiveCompleted.WaitOne()
    Catch ex As Exception
        Console.WriteLine("Error")
        Console.WriteLine(ex.Message)
    End Try
End Sub

Public Sub SendMessage(ByVal ns As NetworkStream, ByVal stringData As String)
    Dim length As Integer = stringData.Length
    Dim headBuffer = New Byte(3) {CByte(length >> 24), CByte(length >> 16), CByte(length >> 8), CByte(length)}

    ns.Write(headBuffer, 0, headBuffer.Length)
    ns.Write(Encoding.UTF8.GetBytes(stringData), 0, stringData.Length)
End Sub

Private Sub ReceiveAsync(ByVal client As TcpClient)
    Try
        Dim state As StateObject = New StateObject()
        state.workSocket = client
        state.bufSize = 4
        state.remainedSize = 4
        client.Client.BeginReceive(state.buffer_size2, 0, 4, 0, New AsyncCallback(AddressOf ReceiveCallback_size), state)
    Catch ex As Exception
        Console.WriteLine("Error")
        Console.WriteLine(ex.Message)
    End Try
End Sub

Sub Main()
    Console.WriteLine("Started")
    _runner = New Thread(AddressOf Run)
    _runner.Start()
End Sub

Private Sub ReceiveCallback_size(ByVal ar As IAsyncResult)
    Dim state As StateObject = CType(ar.AsyncState, StateObject)
    Dim client = state.workSocket
    Dim byteRead As Integer = client.Client.EndReceive(ar)

    If byteRead > 0 Then
        state.remainedSize -= byteRead

        If state.remainedSize > 0 Then
            client.Client.BeginReceive(state.buffer_size2, state.bufSize - state.remainedSize, state.remainedSize, 0, New AsyncCallback(AddressOf ReceiveCallback_size), state)
        Else
            Dim bodySize As Integer = state.buffer_size2(3) Or (state.buffer_size2(2) << 8) Or (state.buffer_size2(1) << 16) Or (state.buffer_size2(0) << 24)
            state.buffer = New Byte(bodySize - 1) {}
            state.bufSize = bodySize
            state.remainedSize = bodySize
            client.Client.BeginReceive(state.buffer, 0, bodySize, 0, New AsyncCallback(AddressOf ReceiveCallback_data), state)
        End If
    Else
        receiveCompleted.[Set]()
    End If
End Sub

Private Sub ReceiveCallback_data(ByVal ar As IAsyncResult)
    Dim state As StateObject = CType(ar.AsyncState, StateObject)
    Dim client = state.workSocket
    Dim byteRead As Integer = client.Client.EndReceive(ar)

    If byteRead > 0 Then
        state.remainedSize -= byteRead

        If state.remainedSize > 0 Then
            client.Client.BeginReceive(state.buffer, state.bufSize - state.remainedSize, state.remainedSize, 0, New AsyncCallback(AddressOf ReceiveCallback_data), state)
        Else
            Dim strData As String = Encoding.ASCII.GetString(state.buffer, 0, state.bufSize)
            NewData(strData)
            state.bufSize = 4
            state.remainedSize = 4
            client.Client.BeginReceive(state.buffer_size2, 0, 4, 0, New AsyncCallback(AddressOf ReceiveCallback_size), state)
        End If
    Else
        receiveCompleted.[Set]()
    End If
End Sub

Public Sub NewData(ByVal strJson As String)
    Console.WriteLine(strJson)
    Dim data As JObject = JObject.Parse(strJson)
    lastMessageTime = data("dt").Value(Of String)()

    If data("r").Value(Of String)() = "event" Then
        Try
            handleMatchData(data)
        Catch e As Exception
            Console.WriteLine(strJson)
            Console.WriteLine(e)
        End Try
    End If
End Sub

Public Class StateObject
    Public workSocket As TcpClient = Nothing
    Public Const BUFFER_SIZE As Integer = 64 * 1024 * 1024
    Public buffer As Byte()
    Public buffer_size2 As Byte() = New Byte(3) {}
    Public sb As StringBuilder = New StringBuilder()
    Public bufSize As Integer = 0
    Public remainedSize As Integer = 0
End Class

问题根源与修复方案

1. 编码不匹配(核心问题)

发送数据用Encoding.UTF8.GetBytes,但接收时用Encoding.ASCII.GetString解码。UTF8字符可能占多字节,ASCII解码会破坏多字节字符结构,导致字符串被截断或乱码,直接引发JSON解析失败。

修复:将接收解码改为UTF8:

' 替换ReceiveCallback_data中的解码代码
Dim strData As String = Encoding.UTF8.GetString(state.buffer, 0, state.bufSize)

2. 消息头字节序验证

当前解析消息头的方式是大端序(网络字节序),如果服务器实际用小端序,会导致计算出的bodySize偏小,从而截断数据。可以打印bodySize值,对比实际响应的JSON字节长度确认。

小端序适配代码:

' 替换ReceiveCallback_size中的bodySize计算
Dim bodySize As Integer = state.buffer_size2(0) Or (state.buffer_size2(1) << 8) Or (state.buffer_size2(2) << 16) Or (state.buffer_size2(3) << 24)

3. 恢复异常捕获

代码中注释掉了Try/Catch块,无法捕获中间错误(如字节序解析错误导致的数组初始化异常),建议恢复捕获逻辑,便于排查问题:

Private Sub ReceiveCallback_size(ByVal ar As IAsyncResult)
    Try
        ' 原有代码
    Catch e As Exception
        Console.WriteLine("Size接收错误: " & e.Message)
        receiveCompleted.[Set]()
    End Try
End Sub

Private Sub ReceiveCallback_data(ByVal ar As IAsyncResult)
    Try
        ' 原有代码
    Catch ex As Exception
        Console.WriteLine("Data接收错误: " & ex.Message)
        receiveCompleted.[Set]()
    End Try
End Sub

4. 优化缓冲区设置

当前重复设置ReceiveBufferSize,保留一次即可,确保系统缓冲区足够:

client.ReceiveBufferSize = 64 * 1024 * 1024
client.Client.ReceiveBufferSize = client.ReceiveBufferSize

内容的提问来源于stack exchange,提问作者Johnny Blanco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 20:57:16