首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C# Socket 傳輸參數化 SQL:將 SqlParameter 序列化為二進制流傳遞

     編輯:程式設計疑難解答

架構圖

Client (WinForm)                          Server (WinForm/Service)
1. 建立 SqlParameter[]                       5. 反序列化為 SqlParameter[]
2. 序列化為 byte[]  ────────────────────►    6. 用 SqlCommand.Parameters.AddRange()
3. Socket.Send(byte[])                       7. 執行 ExecuteNonQuery/Reader
4. 接收結果 byte[]  ◄────────────────────    8. 序列化結果回傳

客戶端:序列化參數陣列

public static byte[] SerializeParameters(SqlParameter[] parameters) {
    using (var ms = new MemoryStream()) {
        var formatter = new BinaryFormatter();
        // SqlParameter 實作 ISerializable,可直接序列化
        formatter.Serialize(ms, parameters);
        return ms.ToArray();
    }
}

// 使用範例
var parameters = new[] {
    new SqlParameter("@Id", 123),
    new SqlParameter("@Name", "Test"),
    new SqlParameter("@Image", imageBytes) { SqlDbType = SqlDbType.VarBinary }
};
byte[] payload = SerializeParameters(parameters);
// 發送:先送 4 字節長度,再送 payload
using (var ns = client.GetStream()) {
    byte[] len = BitConverter.GetBytes(payload.Length);
    ns.Write(len, 0, 4);
    ns.Write(payload, 0, payload.Length);
}

伺服端:反序列化並執行

public static SqlParameter[] DeserializeParameters(byte[] data) {
    using (var ms = new MemoryStream(data)) {
        var formatter = new BinaryFormatter();
        return (SqlParameter[])formatter.Deserialize(ms);
    }
}

// 處理請求
byte[] lenBuf = new byte[4];
ns.Read(lenBuf, 0, 4);
int len = BitConverter.ToInt32(lenBuf, 0);
byte[] payload = new byte[len];
int read = 0;
while (read < len) read += ns.Read(payload, read, len - read);

SqlParameter[] parameters = DeserializeParameters(payload);

using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand("INSERT INTO T(Id,Name,Image) VALUES(@Id,@Name,@Image)", conn)) {
    cmd.Parameters.AddRange(parameters);
    conn.Open();
    int affected = cmd.ExecuteNonQuery();
    // 回傳 affected 等結果...
}

安全性與效能提升方案

問題解決方案
BinaryFormatter 不安全/已過時改用 protobuf-net、MessagePack 或 System.Text.Json (需自訂 SqlParameter 轉 DTO)
直接執行客戶端 SQL 風險極高 (SQL Injection)嚴禁傳輸 SQL 字串。伺服端應預定義 Stored Procedure 或參數化命令,客戶端僅傳參數值。
大型二進制參數 (如圖片) 封包過大分塊傳輸、壓縮 (GZip/Deflate)、或改用檔案伺服器 + 傳 URL。
連線管理使用連線池、非同步 SendAsync/ReceiveAsync、心跳保活。

推薦架構:DTO + JSON/gRPC

// 共用 DTO
public class InsertRequest {
    public int Id { get; set; }
    public string Name { get; set; }
    public byte[] Image { get; set; }
}

// 客戶端
var json = JsonSerializer.Serialize(req);
await stream.WriteAsync(Encoding.UTF8.GetBytes(json));

// 伺服端
var req = JsonSerializer.Deserialize<InsertRequest>(json);
var parameters = new[] {
    new SqlParameter("@Id", req.Id),
    new SqlParameter("@Name", req.Name),
    new SqlParameter("@Image", req.Image) { SqlDbType = SqlDbType.VarBinary }
};

總結

Socket 傳輸參數化 SQL:**嚴禁傳 SQL 字串**,客戶端序列化參數值陣列(或 DTO),伺服端反序列化後注入預定義命令。現代專案建議用 **DTO + JSON/gRPC**,避免 BinaryFormatter 安全風險。

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