简单的跨平台流程来处理Mono中的通信?

我正在开发一个可在Linux,Mac和Windows上运行的Mono应用程序,并且需要应用程序(在单个操作系统上)才能相互发送简单的字符串消息。

具体来说,我想要一个单实例应用程序。 如果尝试启动第二个实例,它将向已经运行的单个实例发送消息。

DBus已经出局了,因为我不希望这是一个额外的要求。 套接字通信似乎很难,因为Windows似乎不允许连接权限。 Mono似乎不支持内存映射文件。 Mono似乎不支持命名管道。 似乎在Mono上不支持IPC。

那么,是否有一种简单的方法可以将单个计算机上的字符串消息发送到适用于每个操作系统的服务器应用程序,而无需权限或其他依赖项?

我在mono-dev邮件列表上写过这篇文章。 考虑了几个通用的进程间消息系统,包括DBus,System.Threading.Mutex类,WCF,Remoting,命名管……结论基本上是单声道不支持Mutex类 (适用于线程间,而不是对于进程间)并没有任何平台无关可用 。

我只能想象出三种可能的解决方案。 都有它们的缺点。 也许有更好的解决方案可用,或者可能只是针对特定目的的更好的解决方案,或者可能存在一些您可以包含在您的应用程序中的跨平台第三方库(我不知道。)但这些是我最好的解决方案。能够找到目前为止:

  • 使用独占锁定在已知位置打开或创建文件。 (FileShare.None)。 每个应用程序都会尝试打开文件,执行其工作并关闭文件。 如果未能打开,则Thread.Sleep(1)再试一次。 这是一种贫民窟,但它可以跨平台工作以提供进程间互斥。
  • 套接字。 第一个应用程序侦听localhost,一些高编号端口。 第二个应用程序尝试侦听该端口,无法打开(因为某些其他进程已经拥有它),因此第二个进程向第一个进程发送消息,该进程已在该端口上侦听。
  • 如果您有权访问事务数据库,或者消息传递系统(sqs,rabbitmq等)使用它。
  • 当然,您可以检测到您所在的平台,然后使用该平台上的任何工作。

在我的ubuntu(10.10 mono版本:2.6.7)上,我尝试使用WCF与BasicHttpBinding,NetTcpBinding和NetNamedPipeBinding进行进程间通信。 前2工作正常,对于NetNamedPipeBinding我收到一个错误:

不支持通道类型IDuplexSessionChannel

在调用ChannelFactory.CreateChannel()方法时。

我也尝试过使用Remoting (这是WCF出来后的一项传统技术)和IpcChannel; 这个msdn页面的例子开始在我的机器上运行没有问题。

我想你不应该在Windows上使用WCF或Remoting时遇到问题,虽然不确定Mac,但是没有任何一个可以测试。 如果您需要任何代码示例,请与我们联系。

希望这会有所帮助,问候

用两种技术解决了我的问题:一个命名的互斥体(以便应用程序可以由不同的用户在同一台​​机器上运行),以及一个消息文件上的观察者。 打开并写入文件以进行通信。 这是一个用IronPython 2.6编写的基本解决方案:

 (mutex, locked) = System.Threading.Mutex(True, "MyApp/%s" % System.Environment.UserName, None) if locked: watcher = System.IO.FileSystemWatcher() watcher.Path = path_to_user_dir watcher.Filter = "messages" watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite watcher.Changed += handleMessages watcher.EnableRaisingEvents = True else: messages = os.path.join(path_to_user_dir, "messages") fp = file(messages, "a") fp.write(command) fp.close() sys.exit(0) 

由于您需要IPC的简单原因,我会寻找另一种解决方案。

此代码已确认可在Linux和Windows上运行。 也应该在Mac上工作:

  public static IList Processes() { IList processes = new List(); foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses()) { Process p = new Process(); p.Pid = process.Id; p.Name = process.ProcessName; processes.Add(p); } return processes; } 

只需遍历列表并查找自己的ProcessName即可。

要向应用程序发送消息,只需使用MyProcess.StandardInput写入应用程序标准输入。 这只适用于您的应用程序是GUI应用程序。

如果您遇到问题,那么您可以使用专门的“锁定”文件。 使用FileSystemWatcher类可以检查它何时发生更改。 这样,第二个实例可以在文件中写入消息,然后第一个实例注意到它发生了变化,并且可以读取文件的内容以获取消息。