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

C# NamedPipe 進程間通訊 (IPC) 完整實作:伺服器/用戶端雙向通訊

     編輯:關於C#

命名管道 是 Windows 高效能、安全、雙向的進程間通訊機制,支援跨機器 (SMB)、模擬、訊息/位元組模式。.NET 提供 NamedPipeServerStream/NamedPipeClientStream (System.IO.Pipes),封裝底層 Win32 API。本文提供完整伺服器/用戶端雙向通訊範例,含非同步讀寫、連線生命週期、例外處理、多執行緒伺服器模式。

核心類別

類別角色關鍵方法
NamedPipeServerStream伺服器端WaitForConnectionAsync, ReadAsync, WriteAsync, Disconnect
NamedPipeClientStream用戶端ConnectAsync, ReadAsync, WriteAsync
PipeDirection方向In, Out, InOut (雙向)
PipeOptions選項Asynchronous (啟用非同步 I/O 完成埠)

1. 伺服器端 (Console App)

using System;
using System.IO.Pipes;
using System.Text;
using System.Threading.Tasks;

class PipeServer
{
    const string PipeName = "np-test-demo";
    static async Task Main()
    {
        Console.WriteLine($"啟動命名管道伺服器: {PipeName}");
        while (true) // 持續接受連線
        {
            using var server = new NamedPipeServerStream(
                PipeName, PipeDirection.InOut, 1, // max 1 instance for demo
                PipeTransmissionMode.Message, PipeOptions.Asynchronous);

            Console.WriteLine("等待用戶端連線...");
            await server.WaitForConnectionAsync();
            Console.WriteLine("用戶端已連線");

            try
            {
                // 讀取訊息 (Message 模式:一次讀一個完整訊息)
                var buffer = new byte[1024];
                int bytesRead = await server.ReadAsync(buffer, 0, buffer.Length);
                string request = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"收到: {request}");

                // 回覆
                string response = $"Server Echo: {request}";
                byte[] respBytes = Encoding.UTF8.GetBytes(response);
                await server.WriteAsync(respBytes, 0, respBytes.Length);
                await server.FlushAsync();
                Console.WriteLine($"已回覆: {response}");

                if (request.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase))
                    break;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"通訊錯誤: {ex.Message}");
            }
            finally
            {
                server.Disconnect();
            }
        }
    }
}

2. 用戶端

using System;
using System.IO.Pipes;
using System.Text;
using System.Threading.Tasks;

class PipeClient
{
    const string PipeName = "np-test-demo";
    static async Task Main()
    {
        using var client = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
        Console.WriteLine("連線至伺服器...");
        await client.ConnectAsync(5000); // 5 秒逾時
        Console.WriteLine("已連線");

        while (true)
        {
            Console.Write("輸入指令 (exit 結束): ");
            string input = Console.ReadLine();
            if (string.IsNullOrEmpty(input)) continue;

            byte[] req = Encoding.UTF8.GetBytes(input);
            await client.WriteAsync(req, 0, req.Length);
            await client.FlushAsync();

            var buffer = new byte[1024];
            int read = await client.ReadAsync(buffer, 0, buffer.Length);
            string resp = Encoding.UTF8.GetString(buffer, 0, read);
            Console.WriteLine($"伺服器回覆: {resp}");

            if (input.Equals("exit", StringComparison.OrdinalIgnoreCase)) break;
        }
    }
}

3. 進階:多執行緒伺服器 (同時處理多用戶端)

class ConcurrentPipeServer
{
    const string PipeName = "np-concurrent";
    static async Task Main()
    {
        var tasks = new List();
        for (int i = 0; i < Environment.ProcessorCount; i++)
        {
            tasks.Add(AcceptLoopAsync(i));
        }
        await Task.WhenAll(tasks);
    }

    static async Task AcceptLoopAsync(int instanceId)
    {
        while (true)
        {
            using var server = new NamedPipeServerStream(
                PipeName, PipeDirection.InOut, -1, // -1 = 不限實例數
                PipeTransmissionMode.Message, PipeOptions.Asynchronous);
            await server.WaitForConnectionAsync();
            _ = HandleClientAsync(server, instanceId); // Fire-and-forget
        }
    }

    static async Task HandleClientAsync(NamedPipeServerStream server, int id)
    {
        try
        {
            var buffer = new byte[4096];
            int read = await server.ReadAsync(buffer, 0, buffer.Length);
            string req = Encoding.UTF8.GetString(buffer, 0, read);
            string resp = $"Instance {id} Echo: {req}";
            byte[] data = Encoding.UTF8.GetBytes(resp);
            await server.WriteAsync(data, 0, data.Length);
            await server.FlushAsync();
        }
        catch { /* log */ }
        finally { server.Disconnect(); }
    }
}

關鍵細節與避坑

問題解決
訊息邊界使用 `PipeTransmissionMode.Message` + `ReadAsync` 一次讀完整訊息;Byte 模式需自行定義長度前綴或分隔符
非同步效能必須加 `PipeOptions.Asynchronous`,否則 `ReadAsync` 會同步阻塞執行緒集區
跨機器用戶端建構函式第一參數改為伺服器主機名/IP (而非 `"."`),需開啟 SMB 連接埠 445、防火牆允許、雙方同網域/工作群組
權限/安全性建構函式可傳 `PipeSecurity` 設定 ACL,限制特定使用者/群組連線
連線中斷偵測`ReadAsync` 回傳 0 表示用戶端關閉;捕獲 `IOException`/`ObjectDisposedException`
大訊息預設緩衝 4KB,大訊息需循環讀寫或增加 `inBufferSize`/`outBufferSize` 參數

替代方案比較

技術優點缺點適用場景
NamedPipe高效能、核心模式、安全、雙向、跨機器僅限 Windows (CoreCLR 3.0+ 支援 Linux 但功能受限)同機/區域網高效能 IPC
MemoryMappedFile極高吞吐、共享記憶體需自行同步 (Mutex/Semaphore)、無內建訊息框架大資料共享、生產者消費者
TCP Loopback跨平台、標準協定網路堆疊開銷、需管理連接埠微服務、容器間通訊
gRPC / NamedPipe (Grpc.Net.NamedPipes)Contract-first、IDL、多語言引入依賴、序列化開銷強型別 RPC、微服務

結語

.NET System.IO.Pipes` 讓命名管道程式化極為簡單:建立 Stream、非同步讀寫、處理連線生命週期。掌握 Message 模式、Asynchronous 選項、多實例伺服器模式、安全性設定 即可構建穩健高效的 IPC 通道。跨平台專案請改用 gRPC 或 TCP;Windows 專有高效能場景,NamedPipe 為首選。

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