C# .NET 5 Socket通信下System.Text.Json反序列化无效值开头错误排查
C# Socket通信JSON反序列化异常问题分析
问题背景
使用C# .NET 5.0开发基于Socket通信的客户端、服务端程序,初期Socket传输对象功能正常,运行一段时间后抛出JSON反序列化异常。
异常详情
Unhandled exception. System.Text.Json.JsonException: 'F' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0. ---> System.Text.Json.JsonReaderException: 'F' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0. at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes) at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker) at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first) at System.Text.Json.Utf8JsonReader.ReadSingleSegment() at System.Text.Json.Utf8JsonReader.Read() at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) --- End of inner exception stack trace --- at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, JsonReaderException ex) at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) at System.Text.Json.JsonSerializer.ReadCore[TValue](JsonConverter jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) at System.Text.Json.JsonSerializer.ReadCore[TValue](Utf8JsonReader& reader, Type returnType, JsonSerializerOptions options) at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, Type returnType, JsonSerializerOptions options) at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options) at LibClient.SimpleClient.start() in C:\Users\---\OneDrive\Documenten\GitHub\Courses\Networking\DistLibrary\LibClient\Client.cs:line 134 at LibClientSimulator.ClientsSimulator.startSimulation() in C:\Users\---\OneDrive\Documenten\GitHub\Courses\Networking\DistLibrary\LibClient\Program.cs:line 62 at LibClientSimulator.Program.Main(String[] args) in C:\Users\---\OneDrive\Documenten\GitHub\Courses\Networking\DistLibrary\LibClient\Program.cs:line 100
相关代码
客户端核心逻辑
while (true) { int b = clientSocket.Receive(buffer); data = Encoding.ASCII.GetString(buffer, 0, b); Message message = JsonSerializer.Deserialize<Message>(data); //报错位置 if(data != null) { if(message.Type == MessageType.Welcome) { Console.WriteLine("Hello"); Console.WriteLine($"Message From Server: {message.Type}"); message.Type = MessageType.BookInquiry; message.Content = bookName; jsonString = JsonSerializer.Serialize(message); msg = Encoding.ASCII.GetBytes(jsonString); clientSocket.Send(msg); } } }
服务端核心逻辑
Message message = JsonSerializer.Deserialize<Message>(data); //Message messageFromBookhelper = JsonSerializer.Deserialize<Message>(databookhelper); if (message.Type == MessageType.Hello) { Console.WriteLine($"{message.Content}"); Console.WriteLine($"Message from Client: {message.Type}\n"); message.Type = MessageType.Welcome; message.Content = ""; msg1 = Encoding.ASCII.GetBytes(JsonSerializer.Serialize(message)); newSock.Send(msg1); } else if(message.Type == MessageType.BookInquiry) { Console.WriteLine($"Book requested from client: {message.Content}"); RequestedBook = message.Content; Booksock.Connect(BookHelperEndpoint); message.Type = MessageType.BookInquiry; message.Content = RequestedBook; msg1 = Encoding.ASCII.GetBytes(JsonSerializer.Serialize(message)); Booksock.Send(msg1); int b1 = Booksock.Receive(buffer); databookhelper = Encoding.ASCII.GetString(buffer, 0, b1); Message messageFromBookhelper = JsonSerializer.Deserialize<Message>(databookhelper); Console.WriteLine(databookhelper); BookData bookdata = JsonSerializer.Deserialize<BookData>(messageFromBookhelper.Content); string bookdataJSON = JsonSerializer.Serialize<BookData>(bookdata); Console.WriteLine($"Book from Bookhelper: {bookdataJSON}"); //此处逻辑执行后触发报错 message.Type = MessageType.BookInquiryReply; message.Content = "Hey"; msg1 = Encoding.ASCII.GetBytes(JsonSerializer.Serialize(message)); newSock.Send(msg1); } data = null; newSock.Send(msg);
问题排查结果
客户端接收的data变量内容为:{"Type":2,"Content":"Hey"}From server: Your message delivered
错误原因
- 服务端存在多余发送逻辑:代码最后一行
newSock.Send(msg)为无效执行,分支逻辑中已经发送了对应响应,该语句会将未赋值/旧的msg内容额外发送给客户端,导致正常JSON消息后拼接了额外内容。 - 未处理TCP粘包问题:TCP是流式传输协议,本身没有消息边界,当前代码直接调用
Receive后就将收到的所有字节转字符串反序列化,若单次收到多个拼接的消息,就会出现JSON格式非法的问题,本次报错开头的F就是额外内容From的首字符。 - 编码使用不合理:ASCII编码无法支持中文等特殊字符,容易出现序列化/反序列化乱码。
解决方法
- 立即修复服务端多余发送逻辑:删除最后一行无效的
newSock.Send(msg);代码,避免额外内容发送。 - 设计消息边界解决粘包问题,二选一即可:
- 长度前缀方案:发送端先发送4字节的整数表示后续JSON内容的字节长度,再发送JSON内容;接收端先读取4字节拿到长度,再读取对应长度的字节后再做反序列化。
- 分隔符方案:每个JSON消息末尾添加特殊分隔符(如
\r\n、自定义不可见字符),接收端将收到的数据流按分隔符拆分后,再对单个完整JSON做反序列化。
- 统一使用UTF-8编码处理JSON字符串的字节转换,避免编码兼容问题。
内容的提问来源于stack exchange,提问作者Poop poop
相关产品推荐
相关产品推荐

