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

C# Socket 訊息傳遞系統實作 (一):架構設計與基本通訊

     編輯:關於C語言

前言:從 RPC 到訊息導向架構

傳統 Web Service 與 .NET Remoting 採用 RPC(遠端程序呼叫)模型,開發者彷彿呼叫本地函式,底層卻隱藏了序列化、網路傳輸、反序列化等複雜細節。而 Socket 程式設計則徹底改變了思維模式:一切皆訊息。資料的收發不再透過回傳值或 out 參數,而是透過明確的訊息收發,這賦予了伺服器主動推送資料給用戶端的能力(如股票即時行情、遊戲狀態同步)。

安全性警示

開放網路埠口即代表潛在攻擊面。惡意用戶可能發送異常封包導致服務當機或嘗試滲透系統。生產環境務必部署於防火牆後方,並實作輸入驗證、速率限制與認證授權機制。

基礎 Socket 伺服器:整數加一服務

同步阻塞版本 (教學用)

using System;
using System.Net;
using System.Net.Sockets;
using System.IO;

public class SimpleTcpServer
{
    public static void Main()
    {
        IPAddress localAddr = IPAddress.Parse("127.0.0.1");
        TcpListener listener = new TcpListener(localAddr, 9999);

        Console.WriteLine("等待連線中...");
        listener.Start();
        
        using (Socket socket = listener.AcceptSocket())
        using (NetworkStream stream = new NetworkStream(socket))
        using (BinaryReader reader = new BinaryReader(stream))
        using (BinaryWriter writer = new BinaryWriter(stream))
        {
            Console.WriteLine("用戶端已連線。");
            int number = reader.ReadInt32();
            number++;
            writer.Write(number);
            Console.WriteLine($"處理完成:{number}");
        }
    }
}

關鍵限制

  • 綁定 127.0.0.1 僅允許本機連線,跨機器需綁定 IPAddress.Any (0.0.0.0) 或具體區網 IP。
  • 單執行緒同步模式一次只能服務一個用戶端,實務不可用。

訊息傳遞框架設計:自訂協議

為了傳遞結構化物件而非原始位元組,我們定義訊息類型列舉與序列化介面:

1. 訊息類型定義

public enum MessageType : int
{
    RequestEmployee = 1,
    Employee = 2
}

2. 訊息介面與實作

public interface ISocketMessage
{
    void Serialize(BinaryWriter writer);
}

public class RequestEmployee : ISocketMessage
{
    public int EmployeeId { get; }

    public RequestEmployee(int id) => EmployeeId = id;
    
    // 反序列化建構子
    public RequestEmployee(BinaryReader reader) => EmployeeId = reader.ReadInt32();

    public void Serialize(BinaryWriter writer)
    {
        writer.Write((int)MessageType.RequestEmployee); // 先寫入訊息類型標識
        writer.Write(EmployeeId);
    }
}

public class Employee : ISocketMessage
{
    public string Name { get; }
    public string Address { get; }

    public Employee(string name, string address)
    {
        Name = name;
        Address = address;
    }

    public Employee(BinaryReader reader)
    {
        Name = reader.ReadString();
        Address = reader.ReadString();
    }

    public void Serialize(BinaryWriter writer)
    {
        writer.Write((int)MessageType.Employee);
        writer.Write(Name);
        writer.Write(Address);
    }
}

3. 用戶端互動邏輯

// 發送請求
RequestEmployee req = new RequestEmployee(15);
req.Serialize(writer);

// 接收回應
MessageType msgType = (MessageType)reader.ReadInt32();
switch (msgType)
{
    case MessageType.Employee:
        Employee emp = new Employee(reader);
        Console.WriteLine($"員工資訊:{emp.Name} - {emp.Address}");
        break;
    default:
        Console.WriteLine($"未知訊息類型:{msgType}");
        break;
}

為何不使用 .NET 內建序列化?

  1. 效能開銷大:BinaryFormatter/SoapFormatter 包含大量型別中繼資料,頻寬浪費嚴重。
  2. 相容性限制:.NET Compact Framework (Pocket PC) 不支援完整序列化機制。
  3. 版本控制困難:組件版本不一致易導致反序列化失敗。

自訂二進位協議雖需手寫序列化碼,但掌控度最高、效能最優、跨平台相容性最佳。

架構觀察:用戶端與伺服器的對稱性

連線建立後,雙方皆持有 NetworkStream,通訊程式碼幾乎完全對稱。差別僅在於連線發起方式(Connect vs Accept),這為後續實作雙向推播奠定基礎。

下一步預告

下篇將深入探討:

  • 伺服器端多執行緒架構支援高併發
  • 動態埠號分配策略解決單一埠口瓶頸
  • 用戶端事件驅動模型整合 WinForms/UI 執行緒
  • 心跳偵測與優雅斷線重連機制
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved