草庐IT

dotnet 6 推荐一个可代替 .NET Remoting 的 IPC 库

lindexi 2023-03-28 原文

本文将来和大家推荐一个基于最友好 MIT 协议的完全在 GitHub 上开源的,可代替 .NET Remoting 的 IPC 本机多进程通讯库

本机内多进程通讯 IPC 不同于跨设备系统的 RPC 通讯方式,大多数的 IPC 通讯都需要处理复杂的用户端环境问题。对于 RPC 通讯来说,大部分时候,服务端都在开发者完全管控的环境下运行。但 IPC 通讯则无论是服务端还是客户端都可能是在用户端运行的。然而用户端上,无论是系统还是其他环境都是十分复杂的,特别是在国内的,魔改的系统,凶狠的杀毒软件,这些都会让 IPC 通讯受到非预期的打断

传统的 dotnet 系的 IPC 手段有很多个,提供给开发使用的顶层框架也有很多,如 .NET Remoting 和 WCF 等。但是在迁移到 dotnet core 时,由于底层运行时机制的变更,如透明代理不再支持类对象只能支持接口的行为变更,就让 .NET Remoting 从机制性不受支持。为了方便将应用迁移到 dotnet core 框架上,可采用 dotnet campus 组织基于最友好的 MIT 协议开源的 dotnetCampus.Ipc 开源库进行本机内多进程通讯

dotnetCampus.Ipc 开源库底层可基于命名管道进行通讯,经过了约千万台设备近一年的测试,发现通过此方式的通讯稳定性极高。开源仓库地址:https://github.com/dotnet-campus/dotnetCampus.Ipc

本文将告诉大家如何使用 dotnetCampus.Ipc 库实现类似 .NET Remoting 的 IPC 通讯效果。无缝替换 .NET Remoting 是做不到的,需要做一定的迁移,还请先看一下本 IPC 是如何使用的

先新建两个项目,分别是 IpcRemotingObjectServerDemo 作为服务端,和 IpcRemotingObjectClientDemo 作为客户端。本质上来说 dotnetCampus.Ipc 库是采用 P2P 模型,没有服务端和客户端之分,只是本文为了对标 .NET Remoting 而强行划分

按照惯例,先通过 NuGet 给 IpcRemotingObjectServerDemo 和 IpcRemotingObjectClientDemo 安装 dotnetCampus.Ipc 库。如上文,由于 dotnetCampus.Ipc 采用 P2P 模型,没有客户端和服务端之分,因此作为客户端和作为服务端的项目安装的 NuGet 包都是相同的

先定义公共约束逻辑,也就是定义的接口。由于 .NET Core 变更了底层透明代理的机制,不再允许透明代理类型,只能透明代理接口。因此本 IPC 库自然比 .NET Remoting 弱化一些,只能定义接口,再定义实现逻辑,而不能和 .NET Remoting 一样,将接口约束和具体实现都在一个类里面实现

interface IFoo
{
    int Add(int a, int b);

    Task<string> AddAsync(string a, int b);
}

本 IPC 库在当前 2020.06 只支持属性和方法的远程过程调用方式,不支持事件和委托。好在事件和委托可以采用反向方法调用间接实现,也就是原本是需要做事件的逻辑,换成调用对方的一个方法的方式。也好在原本在 .NET Remoting 上,委托和事件是比较难使用的,导致了更换起来还是比较清真的

为了和 IPC 库对接,给这个接口标记 IpcPublicAttribute 特性,在特性上面可选带上参数,如下面代码带上了 IgnoresIpcException 表示忽略 IPC 连接和 IPC 通讯本身的异常,但不忽略业务端抛出的异常,再添加 Timeout 表示方法或属性调用的超时时间

using dotnetCampus.Ipc.CompilerServices.Attributes;

[IpcPublic(IgnoresIpcException = true, Timeout = 1000)]
interface IFoo
{
    int Add(int a, int b);

    Task<string> AddAsync(string a, int b);
}

接着编写服务器端的实现逻辑

class Foo : IFoo
{
    public int Add(int a, int b)
    {
        Console.WriteLine($"a({a})+b({b})={a + b}");
        return a + b;
    }

    public async Task<string> AddAsync(string a, int b)
    {
        return await Task.Run(() =>
        {
            Console.WriteLine($"a({a})+b({b})={a + b}");
            return a + b;
        });
    }
}

在服务端编写启动 IPC 的和注册 IFoo 服务的逻辑

using dotnetCampus.Ipc.CompilerServices.GeneratedProxies;
using dotnetCampus.Ipc.Pipes;
using IpcRemotingObjectServerDemo;

var ipcProvider = new IpcProvider("IpcRemotingObjectServerDemo");

ipcProvider.CreateIpcJoint<IFoo>(new Foo());
ipcProvider.StartServer();

Console.Read();

在本 IPC 库里,初始化时可以传入 IPC 名,如以上创建名为 IpcRemotingObjectServerDemo 的 IPC 服务。其他的端即可通过此名称连接上这个 IPC 服务。再接着是通过 CreateIpcJoint 方法注册 IPC 服务

完成注册之后,通过 StartServer 方法开启服务

为了不让主方法退出,导致进程退出,再加上 Console.Read 代码。如此就完成了服务端代码的编写

接下来就是客户端的代码了

需要在客户端定义一个一模一样的接口,当然,更好的方法就是在 VisualStudio 里面添加现有项,将在服务端定义的接口文件作为链接引用进来。在本 IPC 的接口要求是要求接口和命名空间都是一模一样的

定义完成接口之后,就可以开始编写客户端的 IPC 连接逻辑,代码如下。通过以下代码即可建立和服务端的连接

var ipcProvider = new IpcProvider("IpcRemotingObjectClientDemo");

ipcProvider.StartServer();

PeerProxy peer = await ipcProvider.GetAndConnectToPeerAsync("IpcRemotingObjectServerDemo");

以上的 peer 对象就是用来代表服务端的,通过调用 CreateIpcProxy 传入此 peer 对象即可拿到服务端注册的远程 Foo 实例的代理

IFoo foo = ipcProvider.CreateIpcProxy<IFoo>(peer);

接着即可调用此接口对应的方法,代码如下

Console.WriteLine(await foo.AddAsync("a", 1));
Console.WriteLine(foo.Add(1, 2));

除了定义和连接部分和 .NET Remoting 有比较大的差别之外,使用方基本上没有多少差别

这就是 dotnetCampus.Ipc 库的远程对象调用的使用方法,例子代码放在代码仓库 https://github.com/dotnet-campus/dotnetCampus.Ipc

有关dotnet 6 推荐一个可代替 .NET Remoting 的 IPC 库的更多相关文章

  1. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  2. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  3. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  4. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  5. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  6. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  7. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  8. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  9. ruby-on-rails - Rails 中的推荐引擎 - 2

    我想为我的Rails网络应用程序提供推荐功能。特别是,我想向新注册的用户推荐他可能想要关注的其他用户。Rails中是否有用于此目的的引擎/gem?如果没有,我应该从哪里开始构建它?谢谢。 最佳答案 有Coletivogemhttps://github.com/diogenes/coletivo我试了一下。在MySQL上运行。Neo4jhttp://neo4j.org真的很容易实现一个“跟随谁”。事实上,大多数展示其能力的样本都涉及“跟随谁”。快速提示-只有在JRuby上运行时,Neo4j.rb才会很酷。如果不是-使用Neograph

  10. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

随机推荐