首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

序列化與反序列化實戰問題:TCP 傳輸二進制流的記憶體流處理陷阱

     編輯:關於ASP.NET

資料庫同步專案中,使用 BinaryFormatter 將泛型集合序列化為二進制流透過 TCP 傳輸,服務端反序列化寫入資料庫。本文記錄實際遇到的 MemoryStream 位置未重置導致反序列化失敗的問題與解決方案。

情境重現

  • 客戶端:List<DiagramInfo> → BinaryFormatter.Serialize(MemoryStream) → stream.ToArray() → TCP 發送。
  • 服務端:TCP 接收 → 寫入 MemoryStream → BinaryFormatter.Deserialize(MemoryStream)。

客戶端序列化程式碼

private byte[] Serialize(List<DiagramInfo> diagrams)
{
    using (var stream = new MemoryStream())
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(stream, diagrams);
        return stream.ToArray(); // 取得完整位元組陣列
    }
}

服務端反序列化程式碼(含 Bug)

var memStream = new MemoryStream();
do
{
    bytesRead = stream.Read(responseBuffer, 0, bufferSize);
    memStream.Write(responseBuffer, 0, bytesRead);
} while (bytesRead > 0);

// ❌ 錯誤:MemoryStream.Position 位於資料流末尾,Deserialize 會讀取空資料
var formatter = new BinaryFormatter();
var diagrams = (List<DiagramInfo>)formatter.Deserialize(memStream);

根本原因

MemoryStream.Write 後,Position 會移至資料流末尾。Deserialize 從目前 Position 開始讀取,導致讀取到 0 位元組,拋出 SerializationException。

修正方案

// ✅ 修正:反序列化前將 Position 歸零
memStream.Position = 0;
var formatter = new BinaryFormatter();
var diagrams = (List<DiagramInfo>)formatter.Deserialize(memStream);

或使用 memStream.Seek(0, SeekOrigin.Begin)。

最佳實踐補充

  1. 使用 using 區塊:確保 MemoryStream、NetworkStream 正確釋放。
  2. 傳輸長度前綴:TCP 為串流協定,需先傳送 4 位元組長度,接收端再精確讀取指定長度,避免黏包/半包。
  3. 考慮替代序列化器:BinaryFormatter 已標記過時,建議改用 System.Text.Json、protobuf-net、MessagePack 等高效能、跨平台格式。
  4. 異常處理與記錄:反序列化失敗時記錄原始位元組長度、前幾個位元組內容,利於診斷。

修正後完整服務端流程

using (var client = tcpListener.AcceptTcpClient())
using (var netStream = client.GetStream())
using (var memStream = new MemoryStream())
{
    var buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = netStream.Read(buffer, 0, buffer.Length)) > 0)
        memStream.Write(buffer, 0, bytesRead);

    memStream.Position = 0; // 關鍵!
    var formatter = new BinaryFormatter();
    var diagrams = (List<DiagramInfo>)formatter.Deserialize(memStream);
    
    // 處理 diagrams 寫入資料庫...
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved