如何在不使用 SendMessage 的情况下将 "Message" 发送到 .Net 中的另一个进程?

How can I send a "Message" to another process in .Net, without using SendMessage?

我在一台机器上有多个应用程序 运行。一个是工作并将日志写入磁盘以了解它所做的事情(我将称之为 WorkerApp),另一个是总结有关 WorkerApp 状态的支持信息以及更多详细信息(我将称之为仪表板)。

我想从 Dashboard 指示 WorkerApp 采取行动(例如,"Ping remote services")并且我希望 WorkerApp 在收到响应时向 Dashboard 发送 "pong" 响应。

我看过使用 SendMessage 的示例,但这似乎很陈旧(2016 年现在没有更多关于进程间通信的标准吗?)。

我对 Akka.Net but the Remoting 功能的经验很少,它似乎是一个很好的方法,尽管设置它对于我想做的事情来说似乎有点矫枉过正。

目前在 .Net 中两个进程之间进行通信的最简单方法是什么?有没有在本地机器上工作的一些例子?

看看 .Net 远程处理。它比 SendMessage 更现代一些,但不是很多。虽然它很容易使用。我认为这些天执行此操作的官方方法可能是使用 WCF,但我很确定它在引擎盖下是一样的。

.Net remoting 支持各种渠道(Http、TCP),但在您的情况下,我建议使用 IPC remoting。它位于命名管道之上。

如果您 google(.Net 远程处理)可能最简单,但一般的想法是在您的 "server" 应用程序中定义一个 class 从 MarshalByRefObject 派生。完成后,使用 RemotingConfiguration.RegisterWellKnownServiceType.

将其注册到远程处理基础结构

然后您的客户端应用程序可以使用 Activator.CreateObject 创建 class 的实例,然后您就可以开始了。

需要注意的一件事:您似乎需要一个回调机制 - 这样您的 Dashboard 就不会被阻塞等待您的 WorkerApp。这在 .Net 远程处理中受支持,但您需要创建两个通道 - 一个用于传出呼叫(从 Dashboard 到 WorkerApp),另一个用于传入回调。

另一个建议:您的工作人员 class(从 MarshalByRefObject 派生的工作人员)如果也公开接口,将更容易处理。将该接口放在一个可供应用程序使用的 DLL 中,生活会更轻松。

一个建议可能是使用数据库或其他持久性存储来创建一种 'Queue' 仪表板可以将任务插入其中的类型。这也可以存储有关可由工作进程更新的任务的状态。虽然这可以被视为 'overkill',但它带来了多种好处,例如审计、历史报告和服务器 crash/power-off 冗余。它还可能使将来更容易扩展应用程序。

我为此整理了一个 Akka.Net 示例。这是它的样子。

仪表板(发送消息)

using System;
using Akka.Actor;
using Akka.Configuration;

namespace DashBoard
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = ConfigurationFactory.ParseString(@"
akka {  
    actor {
        provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
    }
    remote {
        helios.tcp {
            transport-class = ""Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote""
            applied-adapters = []
            transport-protocol = tcp
            port = 0
            hostname = localhost
        }
    }
}
");

            using (var system = ActorSystem.Create("Dashboard", config))
            {
                var server = system.ActorSelection("akka.tcp://WorkerApp@localhost:8081/user/WorkerAppActor");
                while (true)
                {
                    var input = Console.ReadLine();
                    server.Tell(input);
                }
            }
        }
    }
}

WorkerApp(接收消息)

using System;
using Akka.Actor;
using Akka.Configuration;

namespace WorkerApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = ConfigurationFactory.ParseString(@"
akka {  
    actor {
        provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
    }
    remote {
        helios.tcp {
            transport-class = ""Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote""
            applied-adapters = []
            transport-protocol = tcp
            port = 8081
            hostname = localhost
        }
    }
}
");

            using (var system = ActorSystem.Create("WorkerApp", config))
            {
                system.ActorOf<WorkerAppActor>("WorkerAppActor");

                Console.ReadLine();
            }
        }
    }

    class WorkerAppActor : TypedActor, IHandle<string>
    {
        public void Handle(string message)
        {
            Console.WriteLine($"{DateTime.Now}: {message}");
        }
    }
}