在 .NET 中,同一台机器上的两个进程进行通信的最佳方式是啥?
Posted
技术标签:
【中文标题】在 .NET 中,同一台机器上的两个进程进行通信的最佳方式是啥?【英文标题】:In .NET what's the best way for two processes in the same machine to communicate?在 .NET 中,同一台机器上的两个进程进行通信的最佳方式是什么? 【发布时间】:2009-01-22 08:02:48 【问题描述】:对于同一台机器中的两个进程使用 .NET 进行通信的最佳(或者可能不是最好的——只是好的)方式是什么?
实际上,我正在开发的应用程序中的两个进程甚至不是两个不同的程序;它们只是同一个 EXE 的两个实例。我想做类似单例应用程序的事情,但每个用户都有它(意味着具有多个用户的终端服务器或 Citrix 或 App-V 服务器应该能够启动他们自己的应用程序的单个副本)。如果另一个实例由同一个用户运行,它应该将任务委托给已经运行的实例,然后退出。该程序的每个用户只能运行一个实例。到目前为止,我已经完成了(感谢 ***)使用 Mutex 检测应用程序实例是否已在运行的部分。但我需要第二个应用实例才能将数据发送到第一个应用实例。
我倾向于为此使用命名管道和 WCF 的 NetNamedPipeBinding,但如果您有更好的想法,我将不胜感激。谢谢:)
【问题讨论】:
【参考方案1】:命名管道通常是最好的,但也可以考虑将 MSMQ 用于确保消息随时间传递的“即火即忘”场景。这实际上也取决于您的消息大小。 TCP 会变得很棘手,因为您需要每个用户有一个唯一的端口。
【讨论】:
命名管道会很快,而 WCF 会让它变得非常简单。【参考方案2】:IPC 是我过去为此使用的。这非常容易。 .Net 远程处理是一个不错的选择,但不幸的是它是一个受限选项,因为您不能在 CF 上使用它。
下面是我用来执行进程间通信的类的副本,如果您愿意,可以将它与 MutEx 结合使用,但这不是必需的。只要两个进程中的“pMappedMemoryName”和“pNamedEventName”相同,它就可以正常工作。我尽量让它成为事件驱动的。
只需使用 Poke 方法写入数据,并使用 Peek 方法读取数据,尽管我将其设计为在有新数据可用时自动触发事件。通过这种方式,您可以简单地订阅 IpcEvent 事件,而不必担心昂贵的投票。
public class IpcService
private IServiceContext mContext;
const int maxLength = 1024;
private Thread listenerThread;
private readonly string mMappedMemoryName;
private readonly string mNamedEventName;
public event EventHandler<TextualEventArgs> IpcEvent;
private readonly bool mPersistantListener;
public IpcService(bool pPersistantListener)
: this(pPersistantListener, "IpcData", "IpcSystemEvent")
;
public IpcService(bool pPersistantListener, string pMappedMemoryName, string pNamedEventName)
mPersistantListener = pPersistantListener;
mMappedMemoryName = pMappedMemoryName;
mNamedEventName = pNamedEventName;
public void Init(IServiceContext pContext)
mContext = pContext;
listenerThread = new Thread(new ThreadStart(listenUsingNamedEventsAndMemoryMappedFiles));
listenerThread.IsBackground = !mPersistantListener;
listenerThread.Start();
private void listenUsingNamedEventsAndMemoryMappedFiles()
IntPtr hWnd = EventsManagement.CreateEvent(true, false, mNamedEventName);
while (listenerThread != null)
if (Event.WAITOBJECT == EventsManagement.WaitForSingleObject(hWnd, 1000))
string data = Peek();
EventsManagement.ResetEvent(hWnd);
EventHandler<TextualEventArgs> handler = IpcEvent;
if (handler != null) handler(this, new TextualEventArgs(data));
EventsManagement.SetEvent(hWnd);
Thread.Sleep(500);
HandleManagement.CloseHandle(hWnd);
public void Poke(string format, params object[] args)
Poke(string.Format(format, args));
public void Poke(string somedata)
using (MemoryMappedFileStream fs = new MemoryMappedFileStream(mMappedMemoryName, maxLength, MemoryProtection.PageReadWrite))
fs.MapViewToProcessMemory(0, maxLength);
fs.Write(Encoding.ASCII.GetBytes(somedata + "\0"), 0, somedata.Length + 1);
IntPtr hWnd = EventsManagement.CreateEvent(true, false, mNamedEventName);
EventsManagement.SetEvent(hWnd);
Thread.Sleep(500);
HandleManagement.CloseHandle(hWnd);
public string Peek()
byte[] buffer;
using (MemoryMappedFileStream fs = new MemoryMappedFileStream(mMappedMemoryName, maxLength, MemoryProtection.PageReadWrite))
fs.MapViewToProcessMemory(0, maxLength);
buffer = new byte[maxLength];
fs.Read(buffer, 0, buffer.Length);
string readdata = Encoding.ASCII.GetString(buffer, 0, buffer.Length);
return readdata.Substring(0, readdata.IndexOf('\0'));
private bool mDisposed = false;
public void Dispose()
if (!mDisposed)
mDisposed = true;
if (listenerThread != null)
listenerThread.Abort();
listenerThread = null;
~IpcService()
Dispose();
我希望这会有所帮助。
【讨论】:
好主意!这不会满足我对这个项目的需求,但我将来会使用它。感谢分享。 缺少EventsManagement 类。 您需要添加适当的引用,才能访问 EventsManagement 类。【参考方案3】:我会选择命名管道。
基本上,每个用户都需要一个唯一的端点。与您的 Mutex 一样,您可能会使用用户名来找出要使用的命名管道的名称。这甚至可能取代您对 Mutex 的使用:尝试找出此特定的命名管道是否已经存在,如果存在,则意味着您是第二个要运行的实例。
很难将 TCP 端口映射到用户。
哦,通过使用命名管道,我实际上是在说“通过命名管道进行远程处理”。
【讨论】:
【参考方案4】:Sendmessage/Postmessage 和 Getmessage 是我喜欢的 API。
发送消息:http://pinvoke.net/default.aspx/user32.SendMessage
留言:http://pinvoke.net/default.aspx/user32.PostMessage
GetMessage:http://pinvoke.net/default.aspx/user32.GetMessage
【讨论】:
我会认真考虑不要使用它。这种特殊的通信方式绝对不是 .NET 方式。 上面建议的所有其他内容也有一些或其他性能包袱。 Windows 消息本身非常轻量级......只有 pInvoke 部分可能有害/缓慢。 它易于使用。我认为这是一个有效的答案。也许不适合所有情况,但如果您熟悉使用 API,那么它就有一席之地。它也可能存在一种 .Net 方式来收听消息,我还没有研究过。 我会尽我所能得到的每一个-1,我认为在谈论同一台计算机上的应用程序之间的消息时,它是一个完美的选择和重要的信息。【参考方案5】:.Net Remoting 也可能很方便。它快速且易于实施。
read more on MSDN
【讨论】:
【参考方案6】:您可以将 Mutex 的范围设置为“会话本地”,方法是在其名称前加上“Local\”;阅读MSDN 了解更多信息。通过这种方式,您可以限制每个终端会话的流程实例(好吧,这不是您所要求的)。
【讨论】:
谢谢,但我认为这已经是默认行为了。而且我能够使互斥正常工作;我想要的意见是进程间通信部分。【参考方案7】:另一种方法是使用旧的 DDE(动态数据交换): http://www.codeplex.com/ndde
DDE 建立在 Windows 消息之上,但在它之上是一个抽象层。
(是的,我喜欢我的朋友 WIN32-api);)
【讨论】:
DDE 只不过是 Windows 消息之上的一个奇特层。您指定的链接还提到该库用于旧版应用程序。 就像我写的那样。我仍然喜欢它的简单性。只需几个 API 即可。以上是关于在 .NET 中,同一台机器上的两个进程进行通信的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章
两个 JVM 进程可以使用 ZeroMQ 在同一台机器上进行通信吗?