温故之.NET进程间通信——管道

.Net Core中的管道机制 .Net Core中间件,管道 阅读详情

进程间传递数据,常见的有以下几种方式:

  • 管道:包括命名管道和匿名管道,这篇文章将讲解这种方式
  • 内存映射文件:借助文件和内存空间之间的映射关系,应用(包括多个进程)可以直接对内存执行读取和写入操作,从而实现进程间通信
  • Socket:使用套接字在不同的进程间通信,这种通信方式下,需要占用系统至少一个端口
  • SendMessage:通过窗口句柄的方式来通信,此通信方式基于 Windows 消息 WM_COPYDATA 来实现
  • 消息队列:在对性能要求不高的情况下,我们可以使用 Msmq。但在实际项目中,一般使用ActiveMQ、Kafka、RocketMQ、RabbitMQ等这些针对特定场景优化的消息中间件,以获得最大的性能或可伸缩性优势

其中,管道、内存映射文件、SendMessage的方式,一般用于单机上进程间的通信,在单机上使用这三种方式,比使用 Socket 要相对高效,且更容易控制

而 Socket 、消息队列或其他基于Socket的通信方式,则适用范围更广。它不仅适用于本机进程间的通信,还适用于跨机器(包括跨网段)之间的通信,比如同一个集群里面不同服务器之间的通信、微服务群下各个微服务之间的通信。这也是目前用得最多得方式

虽然在互联网化的今天,本机进程间通信可能用得不多。但在这篇文章中,我们还是有必要了解基于管道的进程间通信方式,后面我们会目前用得比较广泛的一些框架

命名管道

命名管道,它可以在管道服务器和一个或多个管道客户端之间提供进程间通信。其特点如下

  • 命名管道可以是单向的,也可以是双向的
  • 它们支持基于消息的通信(即创建服务端管道时,指定 PipeTransmissionMode.Message
    选项),并允许多个客户端使用相同的管道名称同时连接到服务器端进程
  • 支持模拟,这样连接进程就可以在远程服务器上使用自己的权限

它既可用于本机进程间的通信,也能用于跨机器之间的通信,但实际中很少这样用

跨机器通信,特别是在跨网络的情况下,目前普遍的做法是使用一些通信框架(比如分布式或微服务中,可使用Netty,RPC、REST或Thrift等等),毕竟这些通信框架大都成熟稳定,还经历过商用的考验

用于发送数据的示例代码如下

using System;
using System.IO;
using System.IO.Pipes;

namespace App {
    class Program {
        static void Main(string[] args) {
            /// 第一个参数为管道的名称,第二个参数表示此处的管道用于发送数据
            using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("pipe_demo", PipeDirection.Out)) {
                // 等待连接,程序会阻塞在此处,直到有一个连接到达
                pipeServer.WaitForConnection();

                try {
                    using (StreamWriter sw = new StreamWriter(pipeServer)) {
                        sw.AutoFlush = true;
                        // 向连接的客户端发送消息
                        sw.WriteLine("hello world ");
                    }
                } catch (IOException e) {
                    Console.WriteLine("ERROR: {0}", e.Message);
                }
            }

            Console.ReadLine();
        }
    }
}

用于接收数据的示例代码如下

using System;
using System.IO;
using System.IO.Pipes;

namespace App {
    class Program {
        static void Main(string[] args) {
            /// 第一个参数:"." 表示此管道用于本机。此处用 "localhost"、"127.0.0.1" 也是可以的
            /// 第二个参数:管道的名称
            /// 第三个参数:表示此处的管道用于接收数据
            using (NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "pipe_demo", PipeDirection.In)) {
                pipeClient.Connect();

                using (StreamReader sr = new StreamReader(pipeClient)) {
                    string tmp;
                    while ((tmp = sr.ReadLine()) != null) {
                        Console.WriteLine($"收到数据: {tmp}");
                    }
                }
            }

            Console.ReadLine();
        }
    }
}

关于命名管道的命名,我们这儿使用的是 “pipe_demo” , 推荐采用 “公司名.项目名称.模块名称.管道用途” 的方式命名。这不但可以减小与其他命名管道名称冲突的可能性,还可以让这个管道更具有识别性(通过名称就能知道这个管道是干嘛的)

其中,通过在创建管道时,指定 PipeDirection 选项,可以让管道工作于双工、半双工的通信模式下

public enum PipeDirection {
    // 表示此管道用于接收数据
    In = 1,
    // 表示此管道用于发送数据
    Out = 2,
    // 表示此管道既可发送数据,也可以接收数据
    InOut = 3
}

如果对这种通信方式感兴趣,可以参考 NamedPipeServerStream 与 NamedPipeClientStream 其他的构造函数,来找到更加符合自身业务的模式

匿名管道

匿名管道只能在本机上提供进程间通信。与命名管道相比,其有如下特点

  • 匿名管道需要的开销更少,但提供的服务有限
  • 匿名管道是单向的,且不能通过网络使用,即不能跨网进行通信
  • 仅支持一个服务器实例
  • 匿名管道可用于线程间通信,也可用于父进程和子进程之间的通信,因为管道句柄可以轻松传递给所创建的子进程。

服务端 AnonymousPipeServerStream 定义如下

public sealed class AnonymousPipeServerStream : PipeStream {
    public AnonymousPipeServerStream();
    public AnonymousPipeServerStream(PipeDirection direction);
    public AnonymousPipeServerStream(PipeDirection direction, HandleInheritability inheritability);
    public AnonymousPipeServerStream(PipeDirection direction, HandleInheritability inheritability, int bufferSize);
    public AnonymousPipeServerStream(PipeDirection direction, SafePipeHandle serverSafePipeHandle, SafePipeHandle clientSafePipeHandle);
    public AnonymousPipeServerStream(PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity);

    public SafePipeHandle ClientSafePipeHandle { get; }
    // 此管道的传输模式:在匿名管道中,只支持 PipeTransmissionMode.Byte 这种方式
    public override PipeTransmissionMode TransmissionMode { get; }
    public override PipeTransmissionMode ReadMode { set; }
    public void DisposeLocalCopyOfClientHandle();
    public string GetClientHandleAsString();
    protected override void Dispose(bool disposing);
}

可以看到,其定义了多个构造函数,提供了本机进程中的多种管道通信模式。其中

  • HandleInheritability 用于指明子进程是否可以继承服务器端的底层句柄
  • SafePipeHandle 用于指定客户端和服务端的安全句柄
  • PipeSecurity 用于指定客户端的访问权限

一般情况下,我们只需要使用前三个构造函数即可,后面几个用的很少

客户端 AnonymousPipeClientStream 定义如下

public sealed class AnonymousPipeClientStream : PipeStream {
    public AnonymousPipeClientStream(string pipeHandleAsString);
    public AnonymousPipeClientStream(PipeDirection direction, string pipeHandleAsString);
    public AnonymousPipeClientStream(PipeDirection direction, SafePipeHandle safePipeHandle);

    // 此管道的传输模式:在匿名管道中,只支持 PipeTransmissionMode.Byte 这种方式
    public override PipeTransmissionMode TransmissionMode { get; }
    public override PipeTransmissionMode ReadMode { set; }
}

其中,pipeHandleAsString 参数是父进程在创建此子进程的时候传递的安全句柄

其服务端示例如下

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;

namespace App {
    class Program {
        static void Main(string[] args) {
            Process pipeClient = new Process();
            // 客户端可执行文件的路径
            pipeClient.StartInfo.FileName = @"C:\Users\Jame\source\repos\ConsoleApp4\ConsoleApp4\bin\Debug\ConsoleApp4.exe";

            using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable)) {
                // 将句柄传入
                pipeClient.StartInfo.Arguments =pipeServer.GetClientHandleAsString();
                pipeClient.StartInfo.UseShellExecute = false;
                pipeClient.Start();

                pipeServer.DisposeLocalCopyOfClientHandle();

                try {
                    using (StreamWriter sw = new StreamWriter(pipeServer)) {
                        sw.AutoFlush = true;
                        sw.WriteLine("SYNC");
                        pipeServer.WaitForPipeDrain();

                        Console.Write("[SERVER] Enter text: ");
                        sw.WriteLine(Console.ReadLine());
                    }
                } catch (IOException e) {
                    Console.WriteLine("[SERVER] Error: {0}", e.Message);
                }
            }

            pipeClient.WaitForExit();
            pipeClient.Close();
            Console.WriteLine("[SERVER] Client quit. Server terminating.");

            Console.ReadLine();
        }
    }
}

客户端代码如下

using System;
using System.IO;
using System.IO.Pipes;

namespace App {
    class Program {
        static void Main(string[] args) {
            if (args.Length > 0) {
                // 其中,args[0] 表示传入的句柄
                using (PipeStream pipeClient = new AnonymousPipeClientStream(PipeDirection.In, args[0])) {
                    using (StreamReader sr = new StreamReader(pipeClient)) {
                        string temp;
                        do {
                            Console.WriteLine("[CLIENT] Wait for sync...");
                            temp = sr.ReadLine();
                        }
                        while (!temp.StartsWith("SYNC"));

                        while ((temp = sr.ReadLine()) != null) {
                            Console.WriteLine("[CLIENT] Echo: " + temp);
                        }
                    }
                }
            }

            Console.ReadLine();
        }
    }
}

在匿名管道这个例子中,需要我们先编译客户端的代码,否则可能会有错误

  • 如果客户端还未编译,则父进程会找不到文件
  • 如果客户端已经编译,父进程可启动。但如果我们需要再次编译子进程项目时,会报文件被占用的错误

通过以上的讲解,如果需要使用管道来实现进程间的通信,我们可以按以下方式选择

  • 如果只需要单向通信,且两个进行间的关系为父子进程,则可以使用匿名管道
  • 如果需要双向通信,则使用命名管道
  • 如果我们无法决定到底该选择什么,那就选择命名管道的双向通信方式。在现在的电脑上,命名管道于匿名管道性能的差别我们可以忽略不记。而双向通信的命名管道,既可单向,又可双向,更加灵活
.NET跨进程通信的实现方式 🏆作者:科技、互联网行业优质创作者🏆专注领域:.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造🏆欢迎关注我(),里面有很多技术文章,,能助你快速成长。升职+涨薪!!在WPF中,实现跨进程通信通常可以使用.NET Framework提供的一些功能,例如WCF和命名管道。以下是使用WCF和命名管道实现跨进程通信的示例:** 阅读详情

相关推荐

C# NetworkStream 原理与高可靠网络编程实战

NetworkStream 是 .NET 中封装 TCP 字节流通信的核心抽象,它将底层 Socket 的复杂性(如部分发送、半包接收、连接状态管理)统一映射为标准 Stream 接口,实现‘写即送达、读即有效’的语义契约。其设计严格遵循 TCP 协议的流式特性,故不支持 Seek 和 Length,强调顺序读写与可靠性保障。在工业通信、自定义协议(如 MQTT/PLC)、大文件传输等场景中,NetworkStream 提供比 HttpClient 更底层、比原始 Socket 更安全的平衡点。本文结合粘包

didi9310的博客 393

【微软技术栈】C#.NET 中的管道操作

C#.NET 管道为进程间通信提供了平台。管道分为两种类型:匿名管道。匿名管道在本地计算机上提供进程间通信。与命名管道相比,虽然匿名管道需要的开销更少,但提供的服务有限。匿名管道是单向的,不能通过网络使用。仅支持一个服务器实例。匿名管道可用于线程间通信,也可用于父进程和子进程之间的通信,因为管道句柄可以轻松传递给所创建的子进程。在 .NET 中,可通过使用和类来实现匿名管道。命名管道。命名管道在管道服务器和一个或多个管道客户端之间提供进程间通信。命名管道可以是单向的,也可以是双向的。

Coding life, Coding world, Coding feature. 1554

Java Swing+SqlServer学生成绩管理系统完整实战指南

数据库连接是桌面教务系统开发中的基础环节,JDBC作为Java访问关系型数据库的标准接口,承担着驱动加载、连接建立与SQL执行等核心任务。在Java Swing实现的成绩管理系统中,通过自定义JdbcAdapter类统一管理SqlServer连接参数,能有效避免界面层与数据库逻辑混杂。该类系统常用于学生信息、成绩录入与统计汇总等场景,是Java课程设计和毕业设计的经典选题。本文以一套完整的学生成绩管理系统为例,从类结构、窗体生命周期、JDBC连接串参数,到SQL Server安装、数据库还原、常见连接报错(

weixin_34337381的博客 420

Windows命名管道&getsystem原理学习记录

可以利用Impersonate-NamedPipeClient这个API,通过命名管道的服务端进程模拟客户端进程的访问令牌

include_voidmain的博客 602

SUMO仿真教程(5) —— 使用“XML“语言自定义构建路网

文章目录一.简要介绍1.node file2.edge file3.lane definitions(1)路段细分(2)邻近的对向车道(3)删除边或车道4.type file(1)简要概述(2)edge定义中引用type文件的示例(3)指定车辆种类的速度限制5.connections file(1)简要概述:(2)connection的属性参数(3)删除连接(4)设置连接的优先级(5)同一边的多个连接二.演示示例:1.自定义编写node file2.自定义编写edge file3.自定义编写type fil

weixin_50632459的博客 5014

IC618新手避坑指南:从零在Linux上配置Cadence Virtuoso环境(含cds.lib文件详解)

本文详细介绍了在Linux系统上配置Cadence Virtuoso IC618环境的完整指南,特别针对新手常见问题提供解决方案。重点解析了cds.lib文件的关键配置,包括库路径定义和工艺库管理,并分享了高效工作流设置和典型问题排查技巧,帮助工程师快速搭建稳定的EDA设计环境。

weixin_26805597的博客 551

进程间通信的一个方法(.NET)

环境:VS2005 C# WinForm<br /><br />注:我的方法仅适用于同一系统内的进程,并且相关进程都是您自己编写的C#程序。<br /><br /><br />网上关于C#进程间通信的资料:WM_COPYDATA、共享内存、管道、消息队列、SOCKET...<br />其中WM_COPYDATA是最简单的,但它受制于窗口。当窗口不处在顶层时,WM_COPYDATA就可能失效。共享内存是较为基<br /><br />础的一种办法,但要用好它需要一些技巧。另外小弟对进程间消息传递的及时性非常看重

Jaylon Wang的专栏 3035

共聚焦显微镜的光源、工作原理与选型

共聚焦显微镜作为科研与工业领域中重要的微观成像工具,凭借光源的精准适配性、光学切片技术的三维成像能力,以及对不同工业场景的定制化适配潜力,为半导体检测、工业部件分析、智能制造升级提供了关键技术支撑。深入理解其光源特性、工作原理与选型逻辑,能帮助工程师与技术人员精准匹配设备与生产需求,既保障微观检测的精度与效率,又为产业优化、技术创新筑牢微观观测的基础。

PhotonixBay的博客 1536

温故之.NET进程间通信——内存映射文件

上一篇技术文章中,我们讲解了进程间通信中的管道通信方式,这只是多种进程间通信方式中的一种,这篇文章我们回顾一下另一种进程间通信的方式——内存映射文件。

xnxqwzy的博客 1058

RT-Thread stm32h7使用串口DMA

stm32h7在rtthread中无法使用串口DMA,通过更改驱动代码使其支持串口DMA

qq_35141454的博客 2284

告别Vysor!用Scrcpy在Mac上无线投屏安卓手机(附魅族16th闪退修复实战)

本文详细介绍了如何在Mac上配置和使用开源投屏工具Scrcpy,实现安卓手机无线投屏的高效解决方案。从基础环境准备到高级功能调优,包括无线连接配置、输入控制增强、多设备管理和性能优化等实用技巧,特别针对魅族16th等机型的闪退问题提供了修复方案,帮助用户彻底告别Vysor等商业软件。

weixin_28712661的博客 393

C# 温故而知新:Stream篇(六)

## 一、管道流(PipeStream):进程间的“秘密通道”想象一下,你有两个程序(进程)在跑,一个负责生产数据(比如读取一个大文件),另一个负责消费数据(比如解析这个文件)。管道流就是为此而生的——它就像一根虚拟的“水管”,一头接在进程 A 的出口,另一头接在进程 B 的入口,数据自然地从一头流向另一头。方法——这是 Stream 世界的“潜规则”,写数据后必须刷新缓冲区,否则数据不会立刻通过管道传输。结合起来,就能实现一个“加密管道”——数据在管道里跑的是密文,即使被嗅探也毫无意义。

kaf5ay85R的博客 163

YOLOv12涨点改进 | Neck特征融合改进篇 | YOLOv12引 入 BiFPN双向特征金字塔网络,显著提升了多尺度特征融合效率,目标检测、图像分割、图像分类,助力高效涨点

本文提出了一种基于BiFPN特征融合模块优化的YOLOv12目标检测方法。BiFPN通过引入可学习的权重实现高效的多尺度特征融合,结合双向连接机制提升特征提取能力。实验表明,该方法在COCO数据集上实现了优异的检测性能。文章详细介绍了BiFPN模块的原理、核心代码实现,以及如何将其集成到YOLOv12框架中,包括模块添加、配置文件修改等具体步骤。这种改进方案具有参数少、计算量小等优势,为高效目标检测提供了一种新的技术路径。

Ai缝合怪、助力小伙伴高效发论文 391

Android 知识体系

Android归档前言 前言 感谢: Gityuan:Android系统架构开篇 刘望舒的博客:知识体系

许浑的博客 8192

Autosar_MCAL_Port

PORT Driver就是对微控制器(MCU)的整个PORT模块进行初始化配置。很多端口和管脚被分配有多种不同的功能,即可以进行引脚功能复用,比如通用I/O、adc、pwm、spi等功能。因此,对PORT必须有一个整体的配置和初始化,对各管脚的具体配置和使用取决于微控制器和ECU的引脚功能分配。PORT初始化数据应当尽可能高效地写到每个端口。DIO驱动中所用到的端口的配置和初始化都是在PORT驱动模块中完成的。因此,在使用DIO功能之前,应先进行PORT的初始化。1、PortContainer说明。

不断debug,优化中…… 238

飞牛NAS1.1.19更新后SSH连不上?两步快速恢复连接

飞牛NAS1.1.19版本更新后SSH无法连接😟,实则是官方安全策略升级默认关闭了该服务,本文分享两步实操配置恢复SSH连接💻,还同步了官方的设备安全配置建议,帮助用户兼顾使用与设备防护🔒。

XiaoqiangClub的博客 2092

简述.Net管道通信简介及应用

一、.Net管道通信简介: 1)、管道通信结构: 2)、管道模型 管道模型就使用HttpApplicationFactory对象来创建一个HttpApplication对象来处理这个请求,一个HttpApplication可以包含一系列HTTP module对象。其中最重要的就是HttpModule和HttpHandler: 二、.Net管道通信实际运用 (一)、IIS5 请求Asp.Net ...

Steven的博客 2565

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

c# .net core中间件,生命周期

c# .net core中间件,生命周期

橙-极纪元-JJYCheng 1729

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

进程间通信

进程间通信(interprocess communication,简称 IPC) 指两个进程之间的通信。系统中的每一个进程都有各自的地址空间,并且相互独立、隔离, 每个进程都处于自己的地址空间中。所以同一个进程的不同模块(譬如不同的函数)之间进行通信都是相对简单的,譬如使用全局变量等但是,两个不同的进程之间要进行通信通常是比较难的,因为这两个进程处于不同的地址空间中;通常情况下,大部分的程序是不要考虑进程间通信的,对于一些复杂、大型的应用程序,则会根据实际需要将其设计成多进程程序。

weixin_46829095的博客 1260

C#使用命名管道与其他进程间通讯(一)

命名管道常常用于应用程序之间的通迅,因为不需要进行序列化和反序列化操作,所以效率是非常高的,C#也提供了NamedPipeServerStream与NamedPipeClientStream两个类库用于进程间命名管道通讯,由此写两篇文章记录一下这两个类库的用法。本文章欲构建一个Server端从队列中取数据发送到客户端,文章的实际意义,一方面可以展示这两个类库的使用,另一方面可以对在实际项目中有一定...

f363641380的博客 2628

进程间的几种通信方式

不同的信号有不同的含义和处理方式,操作系统提供了一些默认的信号处理函数,但也允许进程自定义信号处理函数来实现特定的功能。父进程收到信号后,可以根据信号的类型来判断子进程的状态,并做出相应的处理。消息队列是一种进程间通信的机制,用于在不同进程之间传递数据。套接字(socket)是一种用于进程间通信的机制,它提供了一种标准的网络通信接口,使得不同计算机上的进程可以通过网络进行通信。1、可以进行不同计算机间的通信:套接字可以在不同计算机上的进程之间进行通信,使得分布在网络中的进程可以互相发送和接收数据。

qq_39939541的博客 1548

进程/线程间通信方式

这个程序创建了一个管道,然后创建了一个子进程,子进程从管道读取数据并在标准输出上打印出来,父进程向管道写入一条消息。当父进程完成写入后,它关闭管道的写端,这会导致子进程结束循环并退出。接受连接(如果有客户端连接):调用accept函数,等待客户端连接请求,并返回一个新的套接字描述符,用于与该客户端进行通信。在使用短时间内的锁保护共享资源时,相比于互斥锁,自旋锁不会导致线程阻塞,而是一直进行忙等待直到获得锁。常见进程间通信方式包括管道,命名管道,共享内存,信号量,消息队列,套接字和信号七种。

de_se的博客 1390

880-六大进程通信机制总结

1. 什么是进程通信 顾名思义,进程通信( InterProcess Communication,IPC)就是指「进程之间的信息交换」。实际上,「进程的同步与互斥本质上也是一种进程通信」(这也就是待会我们会在进程通信机制中看见信号量和 PV 操作的原因了),只不过它传输的仅仅是信号量,通过修改信号量,使得进程之间建立联系,相互协调和协同工作,但是它「缺乏传递数据的能力」。 虽然存在某些情况,进程之间交换的信息量很少,比如仅仅交换某个状态信息,这样进程的同步与互斥机制完全可以胜任这项工作。但是大多数情况下,「

LINZEYU666的博客 1650

浅谈进程通信

对进程通信的理解

qq_51143945的博客 965
上一篇: ASP.NET CORE [FromServices]控制器方法层面的依赖注入
下一篇: ASP.NET CORE 使用FormData请求接口
.NET跨平台
博客等级 码龄15年 6066粉丝 738原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值