先回顧一下在 "前一篇" 當中有提到基本的使用架構:
+--------------------+ +--------------------+
| Server Process | Named Pipe | Client Process |
| | <----------------------> | |
| NamedPipeServer | \\.\pipe\demo | NamedPipeClient |
+--------------------+ +--------------------+
其中所列舉的範例程式,在 Server 端的 NamedPipeServerStream 使用中,PipeDirection是直接建立 InOut 的。
所以當 Client 同樣也透過 PipeDirection是 InOut 的 NamedPipeClientStream 連線成功後,可以透過一條 Pipe 讓 Server / Client 之間互相拋資料。
如果把該篇的 Server / Client 範例再做點延伸,做成可透過 Console 輸入讓 Server / Client 之間互相 Chat 的範例。
首先,皆在 Server / Client 中設計了兩個 Task,其中一個 Task 透過 StreamReader 不斷的在 Pipe 上讀取資料;另一個 Task 透過 StreamWriter 不斷的接收從 Console 輸入的資料後,寫到 Pipe 當中。
並在其中設計了一個特殊的關鍵字 "exit"。
只要 Server/Client 有任一端有在 Console 中輸入了 "exit" 的文字,並且送出,那 Server / Client 雙方則將停止程式的運作。
下列為 Server 端的程式:
class ChatPipeServer
{
static async Task Main()
{
using var server = new NamedPipeServerStream("demoPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
Console.WriteLine("Waiting for client...");
await server.WaitForConnectionAsync();
Console.WriteLine("Client connected.");
using var reader = new StreamReader(server, new UTF8Encoding(false));
using var writer = new StreamWriter(server, new UTF8Encoding(false)) { AutoFlush = true };
var readTask = Task.Run(async () =>
{
var buffer = new char[1024];
while (server.IsConnected)
{
var count = await reader.ReadAsync(buffer, 0, buffer.Length);
if (count == 0)
break;
var message = new string(buffer, 0, count);
Console.WriteLine($"Client: {message}");
Console.Write("> ");
if (message is null || message.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
}
});
var writeTask = Task.Run(async () =>
{
while (server.IsConnected)
{
Console.Write("> ");
var input = Console.ReadLine();
await writer.WriteAsync(input);
if (input is null || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("User ask \"EXIT\".");
break;
}
}
});
await Task.WhenAny(readTask, writeTask);
Console.WriteLine("Server is closed.");
}
}
下列為 Client 端的程式:
class ChatPipeClient
{
static async Task Main()
{
using var client = new NamedPipeClientStream(".", "demoPipe", PipeDirection.InOut, PipeOptions.Asynchronous);
Console.WriteLine("Connecting...");
await client.ConnectAsync();
Console.WriteLine("Connected to server.");
using var reader = new StreamReader(client, new UTF8Encoding(false));
using var writer = new StreamWriter(client, new UTF8Encoding(false)) { AutoFlush = true };
var readTask = Task.Run(async () =>
{
var buffer = new char[1024];
while (client.IsConnected)
{
var count = await reader.ReadAsync(buffer, 0, buffer.Length);
if (count == 0)
break;
var message = new string(buffer, 0, count);
Console.WriteLine($"Server: {message}");
Console.Write("> ");
if (message is null || message.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
}
});
var writeTask = Task.Run(async () =>
{
while (client.IsConnected)
{
Console.Write("> ");
var input = Console.ReadLine();
await writer.WriteAsync(input);
if (input is null || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("User ask \"EXIT\".");
break;
}
}
});
await Task.WhenAny(readTask, writeTask);
Console.WriteLine("Client is closed.");
}
}
透過 LinqPad 做上述的範例程式的展示 (下圖左邊為 Server 端;右邊為 Client 端):

Server / Client 雙方已經透過 Pipe 連線上,展示的步驟大約如下:
- Client 先發送 "Hi" 的資訊。
- Server 收到後且顯示在 Console 當中。
- Server 發送 "Hello" 的資訊。
- Client 收到後且顯示在 Console 當中。
- Server 發送 "What's your name?" 的資訊。
- Client 收到後顯示在 Console 當中。
- Client 發送 "Client, and you?"。
- Server 收到後顯示在 Console 當中。
- Server 發送 "Server!"。
- Client 收到後顯示在 Console 當中。
- Client 發送 "Ok"。
- Server 收到後顯示在 Console 當中
- Server 發送 "Okay"。
- Client 發送 "Exit"。
- Server / Client 雙方各自結束程式執行。

上述 Chat 範例的運作流程簡單圖解:

從 Server 輸入到 Client 顯示的流程:
Server Console 輸入
│
▼
StreamWriter.Write()
│
▼
Pipe
│
▼
Client StreamReader.Read()
│
▼
Client Console 顯示
反之,從 Client 輸入到 Server 顯示的流程:
Client Console 輸入
│
▼
StreamWriter.Write()
│
▼
Pipe
│
▼
Server StreamReader.Read()
│
▼
Server Console 顯示
所以,運用 Pipe 連線實踐兩個程式之間的互相拋資料,這樣的概念理論上是沒什麼太大的問題的。
I'm a Microsoft MVP - Developer Technologies (From 2015 ~).

I focus on the following topics: Xamarin Technology, Azure, Mobile DevOps, and Microsoft EM+S.
If you want to know more about them, welcome to my website:
https://jamestsai.tw
本部落格文章之圖片相關後製處理皆透過 Techsmith 公司 所贊助其授權使用之 "Snagit" 與 "Snagit Editor" 軟體製作。