【www.bbyears.com--安卓教程】
什么是NamedPipe
Named Pipe(命名管道)是一种有名字的, 建立在pipe server和一个(或多个)pipe client之间的单向或双向的通信管道. 一个命名管道的所有实例都会共享一个相同的pipe name, 但是每个实例都有他自己的缓冲区和句柄(handle), 并且为客户端/服务器的通讯提供一个单独的导管. 这种对实例的使用使得多个pipe client同时地使用相同的named pipe成为可能.
任何进程都可以访问命名管道, 都可以接受安全检查, 这使得命名管道成为关联进程和非关联进程之间通信的一种简单方式.
任何进程都可以既做server, 又做client, 这使得点对点的对等通信成为可能. 正如这里用到的那样, 术语"pipe server”指的是创建named pipe的进程, 术语"pipe client"指的是连接到一个named pipe实例的进程. 供服务器端实例化一个命名管道的函数叫做CreateNamedPipe. 服务器端接受一个连接请求的函数叫做ConnectNamedPipe. 客户端是通过CreateFile 或 CallNamedPipe 函数来连接到命名管道的.
命名管道可以被用来在同一台机器的不同进程间提供通信, 或者在不同机器间通过网络为提供进程间通信. 如果一个服务器处于运行状态, 所有命名管道都可以是可以通过远程连接的. 如果你仅想要在本地使用named pipe, 你可以拒绝NT AUTHORITY\NETWORK帐号的访问, 或者去使用本地的local RPC.
为什么要使用命名管道呢?
为了实现两个程序之间的数据交换。假设下面一个场景。在同一台PC上,程序A与程序B需要进行数据通信,此时我们就可以使用命名管道技术来实现。命名管道的两个对象。NamedPipeClientStream 和 NamedPipeServerStream 对象。请求通信的一方为Client端,发送数据的一方为Server端。
使用NamedPipe来通信,如果Server端崩溃了,不会影响到客户端。
下面我们通过一个例子来说明:
Server端:
UI:
Code:
private NamedPipeServerStream _pipe; private const string PipeName = "PipeSample"; private const int PipeInBufferSize = 4096; private const int PipeOutBufferSize = 65535; private Encoding encoding = Encoding.UTF8; public MainWindow() { InitializeComponent(); _pipe = new NamedPipeServerStream ( PipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous | PipeOptions.WriteThrough, PipeInBufferSize, PipeOutBufferSize ); _pipe.BeginWaitForConnection(WaitForConnectionCallback, _pipe); } private void WaitForConnectionCallback(IAsyncResult ar) { var pipeServer = (NamedPipeServerStream)ar.AsyncState; pipeServer.EndWaitForConnection(ar); var data = new byte[PipeInBufferSize]; var count = pipeServer.Read(data, 0, PipeInBufferSize); if (count > 0) { // 通信双方可以约定好传输内容的形式,例子中我们传输简单文本信息。 string message = encoding.GetString(data, 0, count); Dispatcher.BeginInvoke(new Action(() => { tblRecMsg.Text = message; })); } } private void OnSend(object sender, RoutedEventArgs e) { if (_pipe.IsConnected) { try { string message = txtSendMsg.Text; byte[] data = encoding.GetBytes(message); _pipe.Write(data, 0, data.Length); _pipe.Flush(); _pipe.WaitForPipeDrain(); } catch { } } Close(); }
Client端:
UI:
Code:
private const string PipeServerName = "PipeServer.exe"; private const string PipeName = "PipeSample"; private Encoding encoding = Encoding.UTF8; private NamedPipeClientStream _pipe; private bool _starting = false; public MainWindow() { InitializeComponent(); } private void OnConnect(object sender, RoutedEventArgs e) { if (_starting) { return; } var path = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, PipeServerName); var startInfo = new ProcessStartInfo(path) { UseShellExecute = false, CreateNoWindow = true }; try { var process = Process.Start(startInfo); _pipe = new NamedPipeClientStream ( ".", PipeName, PipeDirection.InOut, PipeOptions.Asynchronous | PipeOptions.WriteThrough ); _pipe.Connect(); _pipe.ReadMode = PipeTransmissionMode.Message; string message = "Connected!"; byte[] data = encoding.GetBytes(message); _pipe.BeginWrite(data, 0, data.Length, PipeWriteCallback, _pipe); _starting = true; } catch (Exception ex) { Debug.Write(ex.StackTrace); } } private void PipeWriteCallback(IAsyncResult ar) { var pipe = (NamedPipeClientStream)ar.AsyncState; pipe.EndWrite(ar); pipe.Flush(); pipe.WaitForPipeDrain(); var data = new byte[65535]; var count = pipe.Read(data, 0, data.Length); if (count > 0) { string message = encoding.GetString(data, 0, count); Dispatcher.BeginInvoke(new Action(() => { tblRecMsg.Text = message; })); } }
需要注意的地方:因为我们在同一台PC上面进行通信,我们只需要将 NamedPipeClientStream 构造参数中pipeServer设为"."即可。另外因为这只是一个示例,所以PipeServer中只传递简单String类型。当然也可以传递其他类型的内容。
运行效果: