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

C# Socket 同步/非同步通訊與多執行緒完整總結

     編輯:關於C#

前言:從基礎 Socket 到生產級架構

Socket 是 TCP/IP 協定的程式介面,是網路通訊的端點。本文系統整理同步/非同步 Socket 模式、多執行緒處理、核心 API 與完整範例,作為 C# 網路程式開發的參考手冊。

一、Socket 基礎概念

位址族與 Socket 類型

列舉常用值說明
AddressFamilyInterNetwork (IPv4), InterNetworkV6 (IPv6)定址方案
SocketTypeStream (TCP), Dgram (UDP), Raw通訊語意
ProtocolTypeTcp, Udp協定

端點與主機解析

// IPEndPoint: IP + Port
var ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8000);

// DNS 解析
IPHostEntry entry = Dns.GetHostEntry("www.example.com");
IPAddress ip = entry.AddressList[0];

二、同步 Socket 伺服器/客戶端完整範例

伺服器端

using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

class SyncServer
{
    Socket _listener;
    Thread _thread;

    public void Start()
    {
        _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _listener.Bind(new IPEndPoint(IPAddress.Any, 8000));
        _listener.Listen(50);

        _thread = new Thread(ListenLoop) { IsBackground = true };
        _thread.Start();
    }

    void ListenLoop()
    {
        while (true)
        {
            try
            {
                Socket client = _listener.Accept(); // 阻塞等待
                byte[] buffer = new byte[1024];
                int received = client.Receive(buffer);
                string msg = Encoding.UTF8.GetString(buffer, 0, received);
                Console.WriteLine($"收到: {msg} from {client.RemoteEndPoint}");
                
                // 回應
                client.Send(Encoding.UTF8.GetBytes("OK"));
                client.Shutdown(SocketShutdown.Both);
                client.Close();
            }
            catch (SocketException ex) { Console.WriteLine(ex); }
        }
    }

    public void Stop()
    {
        _listener?.Close();
        _thread?.Join(1000);
    }
}

客戶端

class SyncClient
{
    public void SendMessage(string ip, int port, string message)
    {
        using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        {
            client.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
            client.Send(Encoding.UTF8.GetBytes(message));
            
            byte[] buffer = new byte[1024];
            int received = client.Receive(buffer);
            Console.WriteLine($"回應: {Encoding.UTF8.GetString(buffer, 0, received)}");
        }
    }
}

三、非同步 Socket 模式 (APM/Begin-End)

核心模式

  • BeginConnect/EndConnect
  • BeginSend/EndSend
  • BeginReceive/EndReceive
  • BeginAccept/EndAccept

非同步伺服器關鍵點

class AsyncServer
{
    Socket _listener;
    const int BufferSize = 4096;

    public void Start(int port)
    {
        _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _listener.Bind(new IPEndPoint(IPAddress.Any, port));
        _listener.Listen(100);
        _listener.BeginAccept(AcceptCallback, _listener);
    }

    void AcceptCallback(IAsyncResult ar)
    {
        Socket listener = (Socket)ar.AsyncState;
        Socket client = listener.EndAccept(ar);
        
        // 立即投遞下一個 Accept
        listener.BeginAccept(AcceptCallback, listener);
        
        // 為新客戶端投遞 Receive
        var state = new StateObject { Client = client, Buffer = new byte[BufferSize] };
        client.BeginReceive(state.Buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, state);
    }

    void ReceiveCallback(IAsyncResult ar)
    {
        var state = (StateObject)ar.AsyncState;
        Socket client = state.Client;
        try
        {
            int bytesRead = client.EndReceive(ar);
            if (bytesRead > 0)
            {
                string msg = Encoding.UTF8.GetString(state.Buffer, 0, bytesRead);
                Console.WriteLine($"收到: {msg}");
                
                // 回應 (同步發送簡化)
                client.Send(Encoding.UTF8.GetBytes("ACK"));
                
                // 繼續接收
                client.BeginReceive(state.Buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, state);
            }
            else { client.Close(); }
        }
        catch { client.Close(); }
    }

    class StateObject { public Socket Client; public byte[] Buffer; }
}

四、現代非同步模式: async/await (TAP)

.NET 4.5+ 推薦使用 Task 為基礎的非同步模式:

public async Task HandleClientAsync(Socket client)
{
    var buffer = new byte[4096];
    while (true)
    {
        int read = await client.ReceiveAsync(new ArraySegment<byte>(buffer), SocketFlags.None);
        if (read == 0) break;
        string msg = Encoding.UTF8.GetString(buffer, 0, read);
        await client.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes("ACK")), SocketFlags.None);
    }
    client.Close();
}

五、多執行緒核心類別

類別/方法用途
Thread手動建立/控制執行緒
ThreadPool.QueueUserWorkItem佇列工作項目至執行緒池
Task / Task<T>現代非同步工作單元
lock / Monitor同步鎖
Interlocked原子操作
AutoResetEvent / ManualResetEvent執行緒訊號
Semaphore / SemaphoreSlim資源計數同步

執行緒生命週期控制

var t = new Thread(Work) { IsBackground = true };
t.Start();
Thread.Sleep(1000);      // 休眠
t.Join(2000);            // 等待結束 (含逾時)
t.Interrupt();           // 中斷阻塞
t.Abort();               // 強制終止 (不推薦,.NET Core 不支援)

六、TCP 通訊核心考量

  • 黏包/拆包:TCP 是位元流,需自訂協定(長度前綴、分隔符、固定長度)。
  • 緩衝區管理:使用 SocketAsyncEventArgs 或 MemoryPool 減少配置。
  • 優雅關閉:Shutdown(SocketShutdown.Send) → 讀取剩餘資料 → Close()。
  • KeepAlive:socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true)。
  • 例外處理:SocketException、ObjectDisposedException、OperationCanceledException。

七、總結與架構建議

  1. 新專案:優先使用 async/await + System.IO.Pipelines 或 Kestrel/SignalR 高階框架。
  2. 維護舊代碼:理解 APM (Begin/End) 與同步阻塞模式的差異與遷移路徑。
  3. 高效能場景:SocketAsyncEventArgs、ValueTask、Memory<T>、IOCompletionPort 原生整合。
  4. 可靠性:重試策略、斷路器、健康檢查、優雅關閉、背壓控制。

Socket 程式設計的核心不在 API 呼叫,而在於協定設計、併發控制、失敗處理、資源管理四大工程課題。掌握基礎,方能駕馭複雜。

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