【C#】解析C#中管道流的使用

时间:2023-03-09 05:12:47
【C#】解析C#中管道流的使用

目录结构:

contents structure [+]

管道为进程间通信提供了一种可能。管道分为两种,一种是匿名管道,另一种是命名管道。

1.匿名管道(anonymous pipe)

匿名管道,匿名管道只提供在本地电脑进程间的通信。匿名管道比命名管道花费的开销更少,但提供的服务也比命名管道的少。匿名管道是单向的,而且不能用于网络通信。匿名管道只支持单服务器实例。

匿名管道不支持消息传输模式(PipeTransmissionMode.Message),仅支持字节传输模式(PipeTransmissionMode.Byte)。

创建匿名管道需要使用AnonymousPipeClientStream和AnonymousPipeServerStream类,下面的案例展示了匿名的管道的用法。
首先创建一个PipeServer.cs文件,其内容如下:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace PipeServer
{
class Program
{
static void Main(string[] args)
{
Process pipeClient1=new Process();
pipeClient1.StartInfo.FileName = @"PipeClient.exe"; //AnonymousPipeServerStream is an one-way pipe. in other words it's only support PipeDirection.In or PipeDirection.Out.
//in this program, we use PipeDirection.Out for send data to clients.
using (AnonymousPipeServerStream pipeServer =
new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable)) { //send the client handle that from AnonymousPipeServerStream to client
pipeClient1.StartInfo.Arguments = pipeServer.GetClientHandleAsString();
pipeClient1.StartInfo.UseShellExecute = false;
pipeClient1.Start(); //closes the local copy of the AnonymousPipeClientStream object's handle
//this method must be call after the client handle has been passed to the client
//if this method isn't called, then the AnonymousPipeServerStream will not receive notice when client dispose of it's PipeStream object
pipeServer.DisposeLocalCopyOfClientHandle(); try
{
using(StreamWriter sw=new StreamWriter(pipeServer)){
//automatic flush
sw.AutoFlush = true; sw.WriteLine("SYNC");
//it'll block util the other end of pipe has been read all send bytes
pipeServer.WaitForPipeDrain(); String temp=null;
while(true){
temp=Console.ReadLine();
//send message to pipeclient from console
sw.WriteLine(temp);
//it'll block util the other end of pipe has been read all send bytes
pipeServer.WaitForPipeDrain();
if(temp=="exit"){
break;
}
}
}
}
catch (IOException e) {
Console.WriteLine("[server] exception:{0}",e.Message);
}
} pipeClient1.WaitForExit();
pipeClient1.Close(); }
}
}

PipeServer.cs

然后创建PipeClient.cs文件,内容如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks; class Program
{
static void Main(string[] args)
{ using (PipeStream pipeClient = new AnonymousPipeClientStream(PipeDirection.In, args[])) { using (StreamReader sr = new StreamReader(pipeClient)) {
String temp = null;
Console.WriteLine("[client] wait for sync ...");
do{
temp = sr.ReadLine();
}while(!temp.StartsWith("SYNC"));
Console.WriteLine("client in");
while ((temp = sr.ReadLine()) != null)
{
Console.WriteLine("[client] receive message: " + temp);
if(temp=="exit"){
break;
}
}
}
Console.Write("[client] Press Enter to exist...");
Console.ReadLine();
}
}
}

PipeClient.cs

这里只展示一个服务端一个客户端,但实际中可以有多个客户端。PipeClient.cs和PipeServer.cs应该在同一个文件夹下面,具体的路径由PipeServer.cs中加载客户端的路径决定,本例中是在同一路径下。然后可以使用csc将其都编译为可执行文件。

2.命名管道(named pipe)

命名管道和匿名管道的功能相似,但他们有如下两点区别:

  • 命名管道既可以支持直接传输模式(PipeTransmissionMode.Byte),也可以支持消息传输模式(PipeTransmissionMode.Message)
  • 命名管道既可以用于本地进程间的通信,也可以用于网络通信。

创建命名管道需要使用NamedPipeServerStream和NamedPipeClientStream类,下面的案例展示了命名管道的用法:
PipeServer.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace PipeServer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Waiting client to connect...\n"); using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut))
{ //wait client to connect
pipeServer.WaitForConnection(); Console.WriteLine("[server] a client connected"); StreamReader reader = new StreamReader(pipeServer);
StreamWriter writer = new StreamWriter(pipeServer);
writer.AutoFlush = true; String line = null;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine("[server] receive message:"+line); writer.WriteLine("I'm fine"); pipeServer.WaitForPipeDrain(); if ("line" == "EXIT")
{
break;
}
}
}; Console.ReadLine();
}
}
}

PipeServer.cs

PipeClient.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace PipeClient
{
class Program
{
static void Main(string[] args)
{
//initialize NamePipeClientStream with serverName,pipeName,pipeDirection
using (NamedPipeClientStream pipeClient =
new NamedPipeClientStream("host path", "testpipe", PipeDirection.InOut)) { Console.WriteLine("[client] Attemping to connect to pipe...");
pipeClient.Connect(); Console.WriteLine("[client] connected to pipe");
Console.WriteLine("[client] There are currently {0} pipe server instances open.",pipeClient.NumberOfServerInstances); StreamWriter writer = new StreamWriter(pipeClient);
writer.AutoFlush = true;
StreamReader reader = new StreamReader(pipeClient); String temp = "";
while (true) {
temp = Console.ReadLine(); //send to server
writer.WriteLine(temp); pipeClient.WaitForPipeDrain(); //read from server
Console.WriteLine("[client] read message from server:"+reader.ReadLine()); if (temp == "EXIT") {
break;
}
}
} Console.ReadLine();
}
}
}

PipeClient.cs

这里需要注意,"."代表本机地址。如果需要到其他服务器,替换就好了。