c# 高级编程 22章520页 【文件和流】【使用管道通信】

使用管道通信

为了 在线程和进程之间通信,在不同的系统之间 快速通信,可以使用管道

.NET中,管道实现为流。因此

  • 可以把字节发送到管道
  • 可以使用流的所有特性,例如
    • 使用 读取器 和 写入器
    • 创建CryptoStreamGZipStream 把加密或压缩的数据写入管道

管道实现为不同的类型:

  1. 命名管道
    • 名称 可以用于连接到 每一端
  2. 匿名管道
    • 不能用于 不同系统 之间的通信
    • 只能用于 一个父子进程 之间的通信 或 不同任务 之间的通信
    • 只能是单向的

示例:使用命名管道 在不同的进程之间通信

  • 一个控制台应用程序 充当服务器,从管道中读取数据
  • 另一个控制台应用程序 把消息写入管道

命名管道 服务器端:读取者

  • NamedPipeServerStream派生自基类PipeStreamPipeStream派生自基类Stream
    • 第一个参数:管道名称 (多个进程可以使用该管道)
    • 第二个参数:管道的方向
      • 读:PipeDirection.In
      • 写:PipeDirection.Out
      • 读写:PipeDirection.InOut
  • NamedPipeServerStream调用WaitForConnection()等待写入方连接
  • NamedPipeServerStream调用Read()把消息读入缓冲区字节数组
  • 命名管道的其他配置:
    • PipeTransmissionMode设置为
      • Byte: 发送一个连续的流
      • Message: 检索每条消息
    • WriteThrough 立即写入管道,不缓存
    • 可以 为输入输出 配置 缓冲区大小
    • 可以 配置 管道安全性。指定 谁允许 读写管道
    • 可以 配置 管道句柄的 可继承性。这对 子进程进行通信 是很重要的
        private static void PipesReader(string pipeName)
        {
            try
            {
                using (var pipeReader = new NamedPipeServerStream(pipeName, PipeDirection.In))
                {
                    pipeReader.WaitForConnection();
                    Console.WriteLine("reader connected");
                    const int BUFFERSIZE = 256;

                    bool completed = false;
                    while (!completed)
                    {
                        byte[] buffer = new byte[BUFFERSIZE];
                        int nRead = pipeReader.Read(buffer, 0, BUFFERSIZE);
                        string line = Encoding.UTF8.GetString(buffer, 0, nRead);
                        Console.WriteLine(line);
                        if (line == "bye") completed = true;
                    }
                }
                Console.WriteLine("completed reading");
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

还可以 使用StreamReader 而不是读取字节数组

        private static void PipesReader2(string pipeName)
        {
            try
            {
                var pipeReader = new NamedPipeServerStream(pipeName, PipeDirection.In);
                using (var reader = new StreamReader(pipeReader))
                {
                    pipeReader.WaitForConnection();
                    Console.WriteLine("reader connected");

                    bool completed = false;
                    while (!completed)
                    {
                        string line = reader.ReadLine();
                        Console.WriteLine(line);
                        if (line == "bye") completed = true;
                    }
                }
                Console.WriteLine("completed reading");
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

命名管道 客户端:写入者

  • NamedPipeClientStream
    • 第一个参数:服务器名称 (因为命名管道 可以在网络上通信)
    • 第二个参数:管道的名称
    • 第三个参数:管道的方向
  • NamedPipeClientStream调用Connect()来连接
  • NamedPipeClientStream调用Write()来写入
        private static void PipesWriter(string serverName, string pipeName)
        {
            try
            {
                using (var pipeWriter = new NamedPipeClientStream(serverName, pipeName, PipeDirection.Out))
                {
                    pipeWriter.Connect();
                    Console.WriteLine("writer connected");

                    bool completed = false;
                    while (!completed)
                    {
                        string input = Console.ReadLine();
                        if (input == "bye") completed = true;

                        byte[] buffer = Encoding.UTF8.GetBytes(input);
                        pipeWriter.Write(buffer, 0, buffer.Length);
                    }
                }
                Console.WriteLine("completed writing");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

还可以 使用StreamWriter 而不是读取字节数组

  • StreamWriter调用WriteLine,把消息发送给服务器
    • 默认情况下,消息不立即发送,而是缓存起来
    • 调用Flush()方法,把消息推到服务器上
    • 也可以立即传送所有消息,这需要配置
        private static void PipesWriter2(string serverName, string pipeName)
        {
            var pipeWriter = new NamedPipeClientStream(serverName, pipeName, PipeDirection.Out);
            using (var writer = new StreamWriter(pipeWriter))
            {
                pipeWriter.Connect();
                Console.WriteLine("writer connected");

                bool completed = false;
                while (!completed)
                {
                    string input = Console.ReadLine();
                    if (input == "bye") completed = true;

                    writer.WriteLine(input);
                    writer.Flush();
                }
            }
            Console.WriteLine("completed writing");
        }

使用匿名管道

AnonymousPipeServerStream的构造函数:

  • 第一个参数:枚举PipeDirection.In, 服务器端 充当 读取器
  • 第二个参数:枚举HandleInheritability.None

通信的另一端 需要知道 管道的 客户端句柄

  • 这个 客户端句柄 通过调用AnonymousPipeServerStreamGetClientHandleAsString()方法得到,并转换成一个字符串
  • 将这个字符串 赋予一个变量
  • 这个变量,以后由充当写入器的 客户端使用

AnonymousPipeClientStream的构造函数:

  • 第一个参数:枚举PipeDirection.In, 客户端 充当 写入器
  • 第二个参数:管道的 客户端句柄

  • 这里,ManualResetEventSlim 是为了在管道的创建时机发出信号

两个任务 用匿名管道 通信

    public class Program
    {
        private string _pipeHandle;
        private ManualResetEventSlim _pipeHandleSet;
        
        public static void Main()
        {
            var p = new Program();
            p.Run();
            Console.ReadLine();
        }

        public void Run()
        {
            _pipeHandleSet = new ManualResetEventSlim(initialState: false);

            Task.Run(() => Reader());
            Task.Run(() => Writer());
        }
        private void Writer()
        {
            Console.WriteLine("anonymous pipe writer");
            _pipeHandleSet.Wait();

            var pipeWriter = new AnonymousPipeClientStream(PipeDirection.Out, _pipeHandle);
            using (var writer = new StreamWriter(pipeWriter))
            {
                writer.AutoFlush = true;
                Console.WriteLine("starting writer");
                for (int i = 0; i < 5; i++)
                {
                    writer.WriteLine($"Message {i}");
                    Task.Delay(500).Wait();
                }
                writer.WriteLine("end");
            }
        }

        private void Reader()
        {
            try
            {
                Console.WriteLine("anonymous pipe reader");
                var pipeReader = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.None);
                using (var reader = new StreamReader(pipeReader))
                {
                    _pipeHandle = pipeReader.GetClientHandleAsString();
                    Console.WriteLine($"pipe handle: {_pipeHandle}");
                    _pipeHandleSet.Set();
                    bool end = false;
                    while (!end)
                    {
                        string line = reader.ReadLine();
                        Console.WriteLine(line);
                        if (line == "end") end = true;
                    }
                    Console.WriteLine("finished reading");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }


另一个 匿名管道的 示例

        private static void AnonymousReader()
        {
            using (var reader = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable))
            {
                Console.WriteLine("using anonymous pipe");
                string pipeHandle = reader.GetClientHandleAsString();
                Console.WriteLine($"pipe handle: {pipeHandle}");

                byte[] buffer = new byte[256];
                int nRead = reader.Read(buffer, 0, 256);
                
                string line = Encoding.UTF8.GetString(buffer, 0, 256);
                Console.WriteLine(line);
            }
        }

        private static void AnonymousWriter()
        {
            Console.WriteLine("using anonymous pipe");
            Console.Write("pipe handle: ");
            string pipeHandle = Console.ReadLine();
            using (var pipeWriter = new AnonymousPipeClientStream(PipeDirection.Out, pipeHandle))
            using (var writer = new StreamWriter(pipeWriter))
            {
                for (int i = 0; i < 100; i++)
                {
                    writer.WriteLine($"Message {i}");
                    Task.Delay(500).Wait();
                }
            }
        }

本文转自 https://juejin.cn/post/7104872006104907783

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值