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

Socket 網路程式設計學習筆記 (5):實體物件序列化傳輸 (SOAP/Binary/Xml)

     編輯:關於.NET

前言

前幾篇僅傳輸文字訊息。實務上常需傳輸複雜物件,將資訊封裝在類別中透過 Socket 傳送,既方便又安全。關鍵在於序列化:將物件轉為位元組陣列才能在網路上傳輸。

三種序列化方式比較

本文以 SOAP 序列化為例示範,其他方式僅需更換 Formatter。

實體類別定義

[Serializable]
public class SocketData
{
    public OperateType OperateType { get; set; }
    public OperateInfo OperateInfo { get; set; }
    public string ConnString { get; set; }
    public string ClientIP { get; set; }
    public string ServerIP { get; set; }

    public SocketData(OperateType type, OperateInfo info, string conn, string clientIP, string serverIP)
    {
        OperateType = type; OperateInfo = info; ConnString = conn; ClientIP = clientIP; ServerIP = serverIP;
    }
}

public enum OperateType { Web = 0, Upgrade, Transfer }
public enum OperateInfo { Send = 0, Error, Success, SendAgain }

關鍵:類別必須標記 [Serializable] 屬性。

訊息邊界處理:長度前綴法

TCP 是串流協定,無訊息邊界。採用「先傳 4 位元組長度,再傳資料」策略:

// 發送端
int msgSize = (int)mem.Length;
byte[] sizeBytes = BitConverter.GetBytes(msgSize);  // int → 4 bytes
stream.Write(sizeBytes, 0, 4);                      // 先傳長度
stream.Write(data, 0, msgSize);                     // 再傳資料

// 接收端
byte[] sizeBuf = new byte[4];
stream.Read(sizeBuf, 0, 4);
int msgSize = BitConverter.ToInt32(sizeBuf, 0);     // 讀取長度

// 循環讀取完整資料
byte[] buffer = new byte[1024];
int offset = 0;
while (msgSize > 0)
{
    int read = stream.Read(buffer, offset, Math.Min(buffer.Length, msgSize));
    mem.Write(buffer, offset, read);
    offset += read;
    msgSize -= read;
}

完整發送/接收實作

發送方法

public static void Send(NetworkStream stream, SocketData data)
{
    IFormatter formatter = new SoapFormatter();
    using (MemoryStream mem = new MemoryStream())
    {
        formatter.Serialize(mem, data);           // 序列化到記憶體流
        byte[] payload = mem.GetBuffer();
        int size = (int)mem.Length;
        
        byte[] sizeBytes = BitConverter.GetBytes(size);
        stream.Write(sizeBytes, 0, 4);            // 寫入長度 (4 bytes)
        stream.Write(payload, 0, size);           // 寫入資料
        stream.Flush();
    }
}

接收方法

public static SocketData Receive(NetworkStream stream)
{
    // 讀取長度
    byte[] sizeBuf = new byte[4];
    if (stream.Read(sizeBuf, 0, 4) != 4) return null;
    int size = BitConverter.ToInt32(sizeBuf, 0);
    if (size <= 0) return null;

    // 讀取完整資料
    using (MemoryStream mem = new MemoryStream())
    {
        byte[] buffer = new byte[1024];
        int remaining = size;
        while (remaining > 0)
        {
            int read = stream.Read(buffer, 0, Math.Min(buffer.Length, remaining));
            if (read == 0) throw new IOException("連線中斷");
            mem.Write(buffer, 0, read);
            remaining -= read;
        }

        // 反序列化
        mem.Position = 0;
        IFormatter formatter = new SoapFormatter();
        return (SocketData)formatter.Deserialize(mem);
    }
}

切換序列化方式

// Binary 序列化 (最小、最快)
IFormatter formatter = new BinaryFormatter();

// Xml 序列化 (需無參數建構函式、public 屬性)
XmlSerializer serializer = new XmlSerializer(typeof(SocketData));

實務建議

  1. 效能優先:.NET 內部通訊用 BinaryFormatter
  2. 相容性優先:異構系統、Web Service 用 SoapFormatter 或 XmlSerializer
  3. 安全性:BinaryFormatter 有反序列化風險,不可信資料請用 Json.NET 或 protobuf-net
  4. 版本容忍:加入 [OptionalField]、實作 ISerializable 控制版本演進

原始碼下載

本文配套原始碼

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方式命名空間格式資料大小相容性適用場景
Xml 序列化System.Xml.SerializationXML中高 (跨平台)異構系統整合
Binary 序列化System.Runtime.Serialization.Formatters.Binary二進位最小低 (.NET 專用).NET 內部高效通訊
SOAP 序列化System.Runtime.Serialization.Formatters.SoapXML (SOAP)大高 (標準協定)Web Service、跨平台