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

Socket 傳輸利器:序列化/反序列化取代字串拼接

     編輯:關於.NET

在 Socket 應用程式中傳遞複雜資料時,常見做法是將各欄位轉字串、用分隔符 (如 `#`) 連接發送。但這有隱患:若使用者輸入內容包含分隔符,解析端將錯誤切割。本文示範使用 序列化/反序列化 (以 JSON 為例) 封裝強型別物件傳輸,徹底解決分隔符衝突、型別保真、擴充性等問題。

核心概念

  • 序列化:物件 → 位元組陣列 (JSON/Binary/Protobuf)。
  • 反序列化:位元組陣列 → 物件。
  • 長度前綴:先發送 4 位元組長度,再發送資料本體,確保接收端一次讀取完整封包。

共用資料契約 (伺服器/客戶端同一定義)


[DataContract(Name = "product")]
public class Product {
  [DataMember(Name = "product_no")]   public string ProductNo { get; set; }
  [DataMember(Name = "product_name")] public string ProductName { get; set; }
  [DataMember(Name = "product_price")] public decimal ProductPrice { get; set; }
}

伺服器端 (WPF + TcpListener)

關鍵代碼


private byte[] SerializeObject(T t) where T : class {
  using (var ms = new MemoryStream()) {
    var ss = new DataContractJsonSerializer(t.GetType());
    ss.WriteObject(ms, t);
    return ms.ToArray();
  }
}

// 非同步接受連線
listener.BeginAcceptTcpClient(ar => {
  var prd = (Product)ar.AsyncState;
  var client = listener.EndAcceptTcpClient(ar);
  var stream = client.GetStream();
  var data = SerializeObject(prd);
  var len = BitConverter.GetBytes(data.Length);
  stream.Write(len, 0, 4);      // 先寫長度
  stream.Write(data, 0, data.Length); // 再寫資料
  client.Close();
  listener.BeginAcceptTcpClient(...); // 繼續監聽
}, prd);

客戶端 (Windows Store App / UWP + StreamSocket)

關鍵代碼


private T DeserializeObject(byte[] buffer) where T : class {
  using (var ms = new MemoryStream(buffer)) {
    ms.Position = 0;
    var ss = new DataContractJsonSerializer(typeof(T));
    return (T)ss.ReadObject(ms);
  }
}

private async void OnClick(object sender, RoutedEventArgs e) {
  var socket = new StreamSocket();
  await socket.ConnectAsync(new HostName(txtHost.Text), txtPort.Text);
  var reader = new DataReader(socket.InputStream) { ByteOrder = ByteOrder.LittleEndian };
  await reader.LoadAsync(4);                    // 讀長度
  int len = reader.ReadInt32();
  await reader.LoadAsync((uint)len);            // 讀資料
  var buf = reader.ReadBuffer(len);
  var prd = DeserializeObject(buf.ToArray());
  tbContent.Text = $"產品編號:{prd.ProductNo}\n產品名稱:{prd.ProductName}\n產品單價:{prd.ProductPrice:C2}";
}

執行結果

伺服器輸入產品資料 → 點擊「開始偵聽」 → 客戶端輸入 IP/Port → 點擊連線 → 即時顯示反序列化後的產品物件,格式完整、型別正確 (decimal 保留小數、日期格式等)。

優勢總結

傳統字串拼接序列化方案
分隔符衝突風險無分隔符,結構化資料
型別資訊流失 (全變字串)完整保留型別 (int/decimal/date/陣列/巢狀物件)
手動解析易出錯框架自動處理,程式碼極簡
擴充欄位需改協定新增屬性即可,舊版相容 (DataMember 預設可選)
跨語言困難JSON/Protobuf 跨平台通用

最佳實務提醒

  1. 長度前綴:TCP 是串流無邊界,務必先傳長度 (或用特定結尾標記),防止粘包/半包。
  2. 版本容錯:使用 DataContract 而非 Serializable,支援選擇性成員、順序無關、版本演進。
  3. 效能考量:高頻/大資料量場景可改用 Protobuf-net、MessagePack、MemoryPack 等二進位序列化器。
  4. 安全性:反序列化不可信資料有風險 (物件注入),生產環境建議驗證簽章或使用安全序列化器。

將序列化引入 Socket 傳輸,是從「手工拼裝」邁向「工業化標準化」的關鍵一步。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved