C# 使用具名管道讓 windows 中的兩個應用程式雙向溝通

要在兩個應用程式之間傳輸訊息可以使用匿名管道(Anonymous Pipes)和具名管道(Named Pipe),匿名管道只能單向且在本機內通訊,而具名管道可以雙向且可以跨裝置溝通,本文將會示範使用具名管道在本機建立 Client 和 Server 端進行溝通。

Server:
    
// 建立名為 testpipe 的雙向管道,最大客戶端數量為 1
NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 1);

// 非同步等待連接
pipeServer.BeginWaitForConnection(new AsyncCallback((target) =>
{
    NamedPipeServerStream? server = target.AsyncState as NamedPipeServerStream;
    server?.EndWaitForConnection(target);
    OnClientConnected(server);
}), pipeServer);

// 連接成功時
void OnClientConnected(NamedPipeServerStream server)
{
    Console.WriteLine("Client connected");

    // 讀取客戶端傳送的資料
    byte[] buffer = new byte[1024];
    Task.Run(() =>
    {
        server.BeginRead(buffer, 0, buffer.Length, new AsyncCallback((target) =>
        {
            NamedPipeServerStream? server = target.AsyncState as NamedPipeServerStream;
            int read = server?.EndRead(target) ?? 0;
            Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, read));
        }), server);
    });


    // 每秒發送一次訊息
    int i = 0;
    while (true)
    {
        Thread.Sleep(1000);

        string str = $"第 {++i} 個訊息\n";
        Console.Write($"Write: {str}");
        server.Write(Encoding.UTF8.GetBytes(str));
    }
}
    

Client:
    
// 建立本機名為 testpipe 的雙向管道
NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut);


Task.Run(() =>
{
    // 建立連線
    pipeClient.Connect();
    Console.WriteLine("Connected to server");

    // 傳送訊息
    string message = "Hello from client";
    pipeClient.Write(Encoding.UTF8.GetBytes(message), 0, message.Length);

    // 持續讀取訊息
    while (true)
    {
        // 中斷連線時停止接收
        if (!pipeClient.IsConnected)
        {
            Console.WriteLine("Pipe is not connected");
            break;
        }

        StreamReader sr = new StreamReader(pipeClient);

        try
        {
            string temp = sr.ReadLine();
            Console.WriteLine($"接收到的訊息: {temp}");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Read message error: {e}");
        }
    }
});
    

在傳送和接收訊息時是使用換行來拆分文字的讀取

範例輸出:

server:
  
Client connected
Hello from client
Write: 第 1 個訊息
Write: 第 2 個訊息
Write: 第 3 個訊息
Write: 第 4 個訊息
Write: 第 5 個訊息



client:
  
Connected to server
接收到的訊息: 第 1 個訊息
接收到的訊息: 第 2 個訊息
接收到的訊息: 第 3 個訊息
接收到的訊息: 第 4 個訊息
接收到的訊息: 第 5 個訊息




參考資料:
How to: Use Named Pipes for Network Interprocess Communication

留言