C# NamePipe使用小结

2016-02-14 10:32:01来源:作者:博客园精华区人点击

最近在一次项目中使用到了C#中命名管道,所以在此写下一篇小结备忘。

为什么要使用命名管道呢?为了实现两个程序之间的数据交换。假设下面一个场景。在同一台PC上,程序A与程序B需要进行数据通信,此时我们就可以使用命名管道技术来实现。命名管道的两个对象。 NamedPipeClientStream 和 NamedPipeServerStream 对象。请求通信的一方为Client端,发送数据的一方为Server端。

使用NamedPipe来通信,如果Server端崩溃了,不会影响到客户端。

下面我们通过一个例子来说明:

Server端:

UI:

<Grid><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/></Grid.ColumnDefinitions><TextBlock Text="Received Message:" Grid.Row="1" Margin="10"/><TextBlock x:Name="tblRecMsg" VerticalAlignment="Center" Grid.Row="1" Grid.Column="1"/><Button Content="Send" Grid.Row="2" Margin="10" Click="OnSend"/><TextBox x:Name="txtSendMsg" VerticalAlignment="Center" Grid.Row="2" Grid.Column="1" Margin="10"/></Grid>

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:

<Grid><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/></Grid.ColumnDefinitions><Button Content="Connect" Margin="10" Click="OnConnect"/><TextBlock Text="Received Message:" Grid.Row="1" Margin="10"/><TextBlock x:Name="tblRecMsg" Grid.Row="1" Grid.Column="1"/></Grid>

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类型。当然也可以传递其他类型的内容。

运行效果:

感谢您的阅读!

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台