这是一个用于本机多进程进行 IPC 通讯的库,此库的顶层 API 是采用 ASP.NET Core 的 MVC 框架,其底层通讯不是传统的走网络的方式,而是通过 dotnetCampus.Ipc 开源项目提供的基于 NamedPipeStream 命名管道的方式进行通讯。相当于替换掉 ASP.NET Core 的底层通讯方式,从走网络换成命名管道的方式。本库的优势是可以使用设计非常好的 ASP.NET Core 的 MVC 框架作为顶层调用 API 层,底层通讯采用可提升传输性能的命名管道,如此可以做到不走网络通讯从而极大减少网络端口占用问题和减少用户端网络环境带来的问题
背景
本机内多进程通讯 IPC 不同于跨设备系统的 RPC 通讯方式,大多数的 IPC 通讯都需要处理复杂的用户端环境问题。对于 RPC 通讯来说,大部分时候,服务端都在开发者完全管控的环境下运行。但 IPC 通讯则无论是服务端还是客户端都可能是在用户端运行的。然而用户端上,无论是系统还是其他环境都是十分复杂的,特别是在国内的,魔改的系统,凶狠的杀毒软件,这些都会让 IPC 通讯受到非预期的打断
传统的 dotnet 系的 IPC 手段有很多个,提供给开发使用的顶层框架也有很多,如 .NET Remoting 和 WCF 等。但是在迁移到 dotnet core 时,由于底层运行时机制的变更,如透明代理不再支持类对象只能支持接口的行为变更,就让 .NET Remoting 从机制性不受支持。为了方便将应用迁移到 dotnet core 框架上,可采用 dotnet campus 组织基于最友好的 MIT 协议开源的 dotnetCampus.Ipc 开源库进行本机内多进程通讯
此 dotnetCampus.Ipc 开源库底层可基于命名管道进行通讯,经过了约 600 万台设备近半年的测试,发现通过此方式的通讯稳定性极高。开源仓库地址:https://github.com/dotnet-campus/dotnetCampus.Ipc
无论是 RPC 还是 IPC 通讯,其顶层提供给开发者使用的 API 层,主流上有两个设计阵营。一个是如 .NET Remoting 一样的传输类对象的方式,此方法可以极大隐藏 RPC 或 IPC 的细节,调用远程进程的对象就和调用本机进程一样。另一个阵营是本文的主角,如 ASP.NET Core 的 MVC 模式,通过路由配合参数传递,进行控制器处理的模式,此方式的优良设计已被 ASP.NET Core 所证明,本文也就不多说了
默认下,如此妙的 ASP.NET Core 的 MVC 层框架是仅提供网络传输的方式。然而在诡异的用户端环境下,将有层出不穷的网络通讯问题,如端口被占用,特殊的软件阻止上网等等。让 ASP.NET Core 从走网络的方式,替换为走命名管道的方式,可以极大提升在用户端的稳定性
再次表扬 ASP.NET Core 的优秀设计,在 ASP.NET Core 里,各个模块分层明确,这也就让更换 ASP.NET Core 里的“通讯传输”(其实本意是 IServer 层)这个工作十分简单
在采用 ASP.NET Core 作为 IPC 的顶层调用时,那此时的通讯方式一定就是 服务端-客户端 的形式。服务端可以采用替换 ASP.NET Core 的“通讯传输”为 dotnetCampus.Ipc 的基于命名管道的传输方式。客户端呢?对 ASP.NET Core 来说,最期望客户端的行为是通过 HttpClient 来进行发起调用。刚好 dotnet 下默认的 HttpClient 是支持注入具体的消息传输实现,通过将 dotnetCampus.Ipc 封装为 HttpClient 的消息传输 HttpMessageHandler 就可以让客户端也走 dotnetCampus.Ipc 的传输。如此封装,相当于在 服务端和客户端 的底层传输,全部都在 dotnetCampus.Ipc 层内,分层图如下,通过 dotnetCampus.Ipc 维持稳定的传输从而隐藏具体的 IPC 细节,业务端可以完全复用原有的知识,无须引入额外的 IPC 知识
充当 IPC 里的服务端和客户端的业务代码将分别与 ASP.NET Core 和 HttpClient 对接。而 ASP.NET Core 和 HttpClient 又与 dotnetCampus.Ipc 层对接,一切的跨进程通讯逻辑都在 dotnetCampus.Ipc 这一层内完成,由 dotnetCampus.Ipc 层维持稳定的 IPC 传输。下面来看看如何使用此方式开发应用
使用方法
接下来将使用 PipeMvcServerDemo 和 PipeMvcClientDemo 这两个例子项目来演示如何使用 ASP.NET Core 的 MVC 层框架加命名管道 NamedPipeStream 做通讯传输的本机内多进程的跨进程通讯 IPC 方式
按照惯例,在 dotnet 系的应用上使用库之前,先通过 NuGet 进行安装。从业务上人为分为服务端和业务端的两个项目,分别安装给服务端用的 dotnetCampus.Ipc.PipeMvcServer 库,和给客户端用的 dotnetCampus.Ipc.PipeMvcClient 库
新建的 PipeMvcServerDemo 和 PipeMvcClientDemo 这两个基于 .NET 6 的例子项目都是先基于 WPF 的项目模板创建,从业务上人为分为服务端和业务端的两个项目其实都是运行在相同的一个计算机内,只是为了方便叙述,强行将 PipeMvcServerDemo 称为服务端项目,将 PipeMvcClientDemo 称为客户端项目
服务端
先从 PipeMvcServerDemo 服务端项目开始写起,在安装完成 dotnetCampus.Ipc.PipeMvcServer 库之后,为了使用上 ASP.NET Core 的 MVC 框架,需要在此 WPF 应用里面初始化 ASP.NET Core 框架
初始化的逻辑,和纯放在服务器上的 ASP.NET Core 服务应用只有一点点的差别,那就是在初始化时,需要调用 UsePipeIpcServer 扩展方法,注入 IPC 的服务替换掉默认的 ASP.NET Core 的“通讯传输”(IServer)层。代码如下
using dotnetCampus.Ipc.PipeMvcServer;
private static void RunMvc(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// 下面一句是关键逻辑
builder.WebHost.UsePipeIpcServer("PipeMvcServerDemo");
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
}
调用 UsePipeIpcServer 扩展方法,需要额外加上 using dotnetCampus.Ipc.PipeMvcServer;
命名空间。在 UsePipeIpcServer 方法里面需要传入一个参数,此参数用于开启的 IPC 服务所使用的服务名,也就是作为命名管道的管道名。服务名的字符串要求是在当前机器上唯一不重复,推荐采用属性的命名法对其命名传入。此后,客户端的代码即可采用此服务名连接上服务端
也仅仅只需加上 UsePipeIpcServer 扩展方法即可完成对服务端的 IPC 的所有配置
客户端
完成服务端的配置之后,可以开始对客户端的配置逻辑,客户端只需要知道服务端的服务名,即如上例子的 "PipeMvcServerDemo"
字符串,即可建立和服务端的通讯。在此库的设计上,可以认为服务端的服务名和传统的 C/S 端应用的服务端地址是等同的,至少需要知道服务端的地址才能连接上
在客户端的任意代码里,可采用 IpcPipeMvcClientProvider 提供的 CreateIpcMvcClientAsync 静态方法传入服务名,拿到可以和服务端通讯的 HttpClient 对象,如以下代码
using dotnetCampus.Ipc.PipeMvcClient;
HttpClient ipcPipeMvcClient = await IpcPipeMvcClientProvider.CreateIpcMvcClientAsync("PipeMvcServerDemo");
以上代码拿到的 ipcPipeMvcClient
对象即可和传统的逻辑一样,进行服务端的请求逻辑,如下文所演示的例子。可以看到客户端的配置逻辑,也只有在初始化时,获取 HttpClient 的逻辑不同
如上面演示的代码,可以看到,无论是客户端还是服务端,初始化的代码都是一句话,没有很多的细节逻辑,方便入手
调用
下面开始演示服务端和客户端调用的例子。为了让客户端能调用到客户端对应的服务内容,需要先在服务端创建对应的服务逻辑。以下将演示 GET 和