TCP Server读取NetworkStream消息时被截断的问题解决
解决TCP监听器接收内容截断的问题
问题根源
你的代码存在两个核心问题导致内容截断:
- 使用固定大小的
toReceive(100000)字节数组,当请求内容(比如案例中Content-Length为106438)超过这个长度时,超出部分会直接丢失 - 仅通过单次
While ns.DataAvailable循环读取数据,TCP是流式传输,数据可能分多批次到达,单次循环无法保证读取完整内容
另外,直接通过字符串拆分text = "{" & text.Split("{")(1)提取JSON的方式非常脆弱,一旦HTTP头格式变化就会出错,应该先解析HTTP头获取Content-Length,再精准读取完整的JSON内容。
修复后的代码
Using client As TcpClient = _server.AcceptTcpClient() Threading.ThreadPool.QueueUserWorkItem(AddressOf NewClient) Using ns As NetworkStream = client.GetStream() ' 第一步:读取并解析HTTP请求头,提取Content-Length Dim headerBuilder As New StringBuilder() Dim buffer(1023) As Byte Dim bytesRead As Integer ' 读取HTTP头直到遇到空行(头与体的分隔标记) Do bytesRead = ns.Read(buffer, 0, buffer.Length) If bytesRead = 0 Then Exit Do headerBuilder.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead)) If headerBuilder.ToString().Contains(vbCrLf & vbCrLf) Then Exit Do End If Loop Dim headerText As String = headerBuilder.ToString() Dim contentLength As Integer = 0 ' 提取Content-Length数值 Dim contentLengthLine As String = headerText.Split(vbCrLf).FirstOrDefault(Function(line) line.StartsWith("Content-Length:")) If contentLengthLine IsNot Nothing Then Integer.TryParse(contentLengthLine.Split(":")(1).Trim(), contentLength) End If ' 第二步:根据Content-Length读取完整的JSON内容 Dim jsonBytes As New List(Of Byte)() Dim totalRead As Integer = 0 While totalRead < contentLength AndAlso ns.CanRead ' 计算剩余需读取的字节,用4096大小的缓冲区平衡效率与内存占用 Dim remaining = contentLength - totalRead Dim readBufferSize = Math.Min(4096, remaining) Dim readBuffer(readBufferSize - 1) As Byte bytesRead = ns.Read(readBuffer, 0, readBufferSize) If bytesRead = 0 Then Exit Loop jsonBytes.AddRange(readBuffer.Take(bytesRead)) totalRead += bytesRead End While ' 处理完整的JSON数据 If totalRead >= My.Settings.minLenghtForSuccess Then Dim jsonText As String = Encoding.UTF8.GetString(jsonBytes.ToArray()) Dim jsonObj As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonText) Dim ipOrigine As String = jsonObj("data")("IPAddress") Dim dispositivoOrigine As String = jsonObj("data")("DeviceName") Dim canaleOrigine As String = jsonObj("data")("ChannelName") Dim targa As String = jsonObj("data")("PicData")("PlateInfo")(0)("SnapId") ' 这里添加你的业务逻辑处理代码 End If End Using End Using
关键改动说明
- HTTP头解析:先读取完整的HTTP请求头,明确获取
Content-Length字段的值,知道需要读取的JSON内容总长度 - 动态缓冲区:使用
List(Of Byte)累积读取的字节,彻底摆脱固定大小数组的限制 - 分批次读取:循环读取直到获取到
Content-Length指定的所有字节,适配TCP流式传输的特性,确保数据完整 - 严谨的JSON解析:直接使用读取到的完整JSON字符串解析,避免了原代码中脆弱的字符串拆分逻辑
内容的提问来源于stack exchange,提问作者Gabriele Cozzolino
相关产品推荐
相关产品推荐

