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
相关产品推荐
相关产品推荐

