适合我情况的 IPC 形式
Posted
技术标签:
【中文标题】适合我情况的 IPC 形式【英文标题】:A form of IPC that works for my situation 【发布时间】:2012-02-17 15:07:45 【问题描述】:我需要通知 1 多个客户端执行任务(重新加载)。服务器可能在也可能不在任何给定时间点运行。 (出于这个原因,我很难定义谁是客户端,谁是服务器。)
在任何给定时间,服务器都可能开始运行。当服务器自行关闭时,它会通知所有客户端执行他们的任务。
我尝试使用NamedPipeServerStream
并在“客户端”上运行多个实例(请记住这种关系很奇怪,请耐心等待)。不幸的是,我只能为任何给定的服务器名称创建一个管道服务器。所以这没有用。我可以让客户端不断检查服务器,但如果我要开始轮询,那么我不妨直接轮询数据库。
我的情况大致类似于观察者模式。我不需要动态订阅/取消订阅。我确实希望服务器向所有正在运行的客户端推送通知以执行任务。
我怎样才能做到这一点?请记住,我必须使用 IPC 执行此操作。服务器/客户端在不同的进程下运行,并且始终在同一台机器上。
【问题讨论】:
服务器进程和许多客户端进程是否保证在同一台机器上,或者服务器是否可以驻留在网络地址上? @ScottChamberlain - 同一台机器。如果 UDP 或某种形式的网络通信是唯一的方法,那么我愿意接受。 保证是同一台机器打开了更多选择。 【参考方案1】:要解决轮询问题,您可以创建一个名为 ManualResetEvent 的客户端进程将侦听。客户端将启动一个线程然后等待事件,当服务器启动时,它将发出事件信号并让所有客户端启动他们的监听代码,该代码可以像你现在一样打开一个命名管道。查看EventWaitHandle.GetAccessControl MSDN 页面,了解如何创建已命名的 ManualResetEvent 的示例。
对于您的I can only create one Pipe server for any given server name.
问题,如果有多个服务器在运行,客户端应该如何知道要连接到哪个服务器?你说这是一个服务器到*客户端的关系。如果你要运行多个服务器,你需要一种方法来告诉客户端它应该监听哪个服务器。
【讨论】:
我没有意识到您可以跨进程边界触发事件。你确定这行得通吗?关于第二部分,只有一台服务器。客户端只响应这 1 个服务器。 是的,我链接的页面上的示例正是这样做的,它在同一程序的两次执行中发出 ManualResetEvent 信号(第一次启动是“服务器”(doesNotExist = true
),第二次启动检测到 Named ManualResetEvent 已存在 (doesNotExist = false
) 将自身转入“客户端”。)
@Scott 我不知道 .Net 的 EventWaitHandle 很容易让您附加到命名事件 - 我一直像白痴一样使用 p/invoke。如果我可以投票两次,我会的。【参考方案2】:
因为您指定所有进程都保证在同一台机器上,所以我可能会考虑使用 Windows named event。您的客户端和服务器可以调用OpenEvent,如果尚未创建事件,请调用CreateEvent。这将使您能够对每个事件释放多少客户端进行一些控制(使用脉冲事件、设置/重置等),并且还允许您在服务器不存在的情况下打开客户端。
正如 Scott 建议的那样,要在 c# 中轻松完成此操作,请使用名为 EventWaitHandle
的 .net,通过调用带有字符串的构造函数(例如 this one)。这将为您创建系统范围的同步对象。该特定构造函数还会告诉您是您是第一个请求事件的人(您创建了它),还是它已经存在。
【讨论】:
【参考方案3】:使用命名共享内存是完成一对多通信的一种方式。服务器可以创建共享内存,一个或多个客户端可以打开并读取它。 An example (in C) is shown here。另外,a .NET example is shown here。
只要至少有一个进程有一个打开的句柄,共享内存就会存在。从 OP 看来,这听起来像是一个有用的功能,因为即使在服务器进程关闭后内存也可以继续存在(只要至少有一个客户端仍然打开它)。 .NET 示例还展示了如何持久化信息,如果它必须比进程更长寿,这将很有用。
根据所需的时间,客户端可以定期读取内存以获取必要的信息。或者,如果存在时间更紧迫的情况,您可以使用命名信号量来向客户端发出信号以执行必要的操作。使用信号量作为同步对象,您可以通过将释放计数设置为大于 1 的值来向多个客户端发出信号。
【讨论】:
以上是关于适合我情况的 IPC 形式的主要内容,如果未能解决你的问题,请参考以下文章