• C# NamePipe使用小结


    最近在一次项目中使用到了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类型。当然也可以传递其他类型的内容。

    运行效果:

    感谢您的阅读!

  • 相关阅读:
    单例模式
    简单工厂模式
    MSSQL编程笔记三 left join on 和 left join where区别
    冒泡排序、选择排序和插入排序
    Extjs性能问题
    C#委托入门
    metro css for cnblogs
    委托、事件与Observer设计模式
    C# 集合类[转]
    工厂方法模式(Factory Method Pattern)
  • 原文地址:https://www.cnblogs.com/yang-fei/p/4696689.html
Copyright © 2020-2023  润新知