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

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

错误原因

  1. 服务端存在多余发送逻辑:代码最后一行newSock.Send(msg)为无效执行,分支逻辑中已经发送了对应响应,该语句会将未赋值/旧的msg内容额外发送给客户端,导致正常JSON消息后拼接了额外内容。
  2. 未处理TCP粘包问题:TCP是流式传输协议,本身没有消息边界,当前代码直接调用Receive后就将收到的所有字节转字符串反序列化,若单次收到多个拼接的消息,就会出现JSON格式非法的问题,本次报错开头的F就是额外内容From的首字符。
  3. 编码使用不合理:ASCII编码无法支持中文等特殊字符,容易出现序列化/反序列化乱码。

解决方法

  • 立即修复服务端多余发送逻辑:删除最后一行无效的newSock.Send(msg);代码,避免额外内容发送。
  • 设计消息边界解决粘包问题,二选一即可:
    • 长度前缀方案:发送端先发送4字节的整数表示后续JSON内容的字节长度,再发送JSON内容;接收端先读取4字节拿到长度,再读取对应长度的字节后再做反序列化。
    • 分隔符方案:每个JSON消息末尾添加特殊分隔符(如\r\n、自定义不可见字符),接收端将收到的数据流按分隔符拆分后,再对单个完整JSON做反序列化。
  • 统一使用UTF-8编码处理JSON字符串的字节转换,避免编码兼容问题。

内容的提问来源于stack exchange,提问作者Poop poop

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:39:02