【转】C#管道通信

http://outofmemory.cn/code-snippet/441/System-IO-usage-guandao-process-jiantongxin-System-IO-Pipes-usage

https://www.cnblogs.com/yang-fei/p/4696689.html

管道的用途是在同一台机器上的进程之间通信,也可以在同一网络不同机器间通信。在.Net中可以使用匿名管道和命名管道。管道相关的类在System.IO.Pipes命名空间中。.Net中管道的本质是对windows API中管道相关函数的封装。

使用匿名管道在父子进程之间通信:

匿名管道是一种半双工通信,所谓的半双工通信是指通信的两端只有一端可写另一端可读;匿名管道只能在同一台机器上使用,不能在不同机器上跨网络使用。

匿名管道顾名思义就是没有命名的管道,它常用于父子进程之间的通信,父进程在创建子进程是要将匿名管道的句柄作为字符串传递给子进程,看下例子:

父进程创建了一个AnonymousPipeServerStream,然后启动子进程,并将创建的AnonymousPipeServerStream的句柄作为参数传递给子进程。如下代码:

Process process = new Process();
process.StartInfo.FileName = "child.exe";
 //创建匿名管道流实例,
using (AnonymousPipeServerStream pipeStream =
    new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable)) {
 //将句柄传递给子进程
    process.StartInfo.Arguments = pipeStream.GetClientHandleAsString();
    process.StartInfo.UseShellExecute = false;
    process.Start();
 //销毁子进程的客户端句柄?
    pipeStream.DisposeLocalCopyOfClientHandle();

    using (StreamWriter sw = new StreamWriter(pipeStream)) {
        sw.AutoFlush = true;
//向匿名管道中写入内容
        sw.WriteLine(Console.ReadLine());
    }
}

process.WaitForExit();
process.Close();

子进程声明了一个AnonymousPipeClientStream实例,并从此实例中读取内容,如下代码:

using (StreamReader sr = new StreamReader(
    new AnonymousPipeClientStream(PipeDirection.In, args[0]))) {
    string line;
    while ((line = sr.ReadLine()) != null) {
        Console.WriteLine("Echo: {0}", line);
    }
}

这个程序要在cmd命令行中执行,否则看不到执行效果,执行的结果是在父进程中输入一行文本,子进程输出Echo:文本。

命名管道:

命名管道的功能比匿名管道更强大,可以在进程之间做双工通信(即通信的两个进程都是既可以读也可写的);命名管道也可以实现跨网络在不同机器之间进行通信。可以在多线程中创建多个NamedPipeServerStream实例,为多个client端服务。另外命名管道还支持消息传输,这样client端可以读取任意长度的消息,而无须知道消息的长度。

如下服务端进程代码:

using (NamedPipeServerStream pipeStream = new NamedPipeServerStream("testpipe"))
{
    pipeStream.WaitForConnection();

    using (StreamWriter writer = new StreamWriter(pipeStream))
    {
        writer.AutoFlush = true;
        string temp;

        while ((temp = Console.ReadLine()) != "stop") {
            writer.WriteLine(temp);
        }
    }
}

如下客户端进程代码:

static void Main(string[] args)
{
    using (NamedPipeClientStream pipeStream = new NamedPipeClientStream("testpipe"))
    {
        pipeStream.Connect();
        //在client读取server端写的数据
        using (StreamReader rdr = new StreamReader(pipeStream))
        {
            string temp;
            while ((temp = rdr.ReadLine()) != "stop")
            {
                Console.WriteLine("{0}:{1}",DateTime.Now,temp);
            }
        }
    }

    Console.Read();
}

上面代码执行结果是服务端输入文本,客户端显示接受到文本的时间和文本内容。上面说了命名管道是全双工通信的,所以你也可以让客户端写内容,而服务端接受内容,代码大同小异。

基于消息传输的命名管道:

基于消息的命名管道可以传递不定长的内容,而无需传递内容长度或者结束符,上面非基于消息的传输我们都是在向管道中输入一段文本,使用WriteLine方法以回车换行作为结束符传输信息,而管道的另一端再使用ReadLine方法以读取到回车换行符作为一个消息传递结束的标志;而在使用基于消息传输时就不必这么做了。如下示例:

服务端代码:

static void Main(string[] args)
{
    UTF8Encoding encoding = new UTF8Encoding();
    string message1 = "Named Pipe Message Example.";
    string message2 = "Another Named Pipe Message Example.";
    Byte[] bytes;
    using (NamedPipeServerStream pipeStream = new
            NamedPipeServerStream("messagepipe", PipeDirection.InOut, 1,
            PipeTransmissionMode.Message, PipeOptions.None))
    {
        pipeStream.WaitForConnection();

        // Let’s send two messages.
        bytes = encoding.GetBytes(message1);
        pipeStream.Write(bytes, 0, bytes.Length);
        bytes = encoding.GetBytes(message2);
        pipeStream.Write(bytes, 0, bytes.Length);

    }
}

客户端代码:

static void Main(string[] args)
{
    Decoder decoder = Encoding.UTF8.GetDecoder();
    Byte[] bytes = new Byte[10];
    Char[] chars = new Char[10];
    using (NamedPipeClientStream pipeStream =
            new NamedPipeClientStream("messagepipe"))
    {
        pipeStream.Connect();
        pipeStream.ReadMode = PipeTransmissionMode.Message;
        int numBytes;
        do
        {
            string message = "";

            do
            {
                numBytes = pipeStream.Read(bytes, 0, bytes.Length);
                int numChars = decoder.GetChars(bytes, 0, numBytes, chars, 0);
                message += new String(chars, 0, numChars);
            } while (!pipeStream.IsMessageComplete);

            decoder.Reset();
            Console.WriteLine(message);
        } while (numBytes != 0);
    }
}

基于消息传递信息需要在构造NamedPipeServerStream时指定PipeTransmissionMode为PipeTransmissionMode.Message;而在客户端接收时也需指定NamedPipeClientStream的ReadMode属性为PipeTransmissionMode.Message

以上只是管道使用的简单实例,真正使用时还需要考虑多线程访问控制,权限控制等。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C#管道通信是一种进程间通信的机制,它允许不同的进程之间进行数据交换。管道通信的原理是通过创建一个命名管道来实现进程间的通信。 在C#中,可以使用命名管道来实现进程间通信。命名管道是一种特殊的文件,可以用于进程之间的双向通信。它可以在同一台计算机上的不同进程之间进行通信,也可以在不同计算机上的进程之间进行通信。 管道通信的原理如下: 1. 创建管道:首先,一个进程需要创建一个命名管道。这可以通过使用命名管道类(NamedPipeServerStream)来实现。进程可以指定一个唯一的管道名称,并设置管道的属性,如读写权限、缓冲区大小等。 2. 等待连接:创建管道后,进程需要等待其他进程来连接。这可以通过命名管道类的等待连接方法(WaitForConnection)来实现。当有其他进程连接到该管道时,该方法将返回并允许进程进行通信。 3. 通信:一旦连接建立,进程可以使用命名管道类提供的读取和写入方法来进行数据交换。一个进程可以通过写入方法(Write)将数据发送到管道中,而另一个进程则可以通过读取方法(Read)从管道中读取数据。 4. 断开连接:当通信完成后,可以通过关闭管道来断开连接。这可以通过调用命名管道类的关闭方法(Close)来实现。 总的来说,C#管道通信通过创建命名管道来实现进程间的通信,其中一个进程充当管道的服务端,另一个进程充当管道的客户端。服务端等待客户端连接,然后进行数据交换,最后断开连接。这样,不同的进程就可以通过管道进行双向通信了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值