在.NET什么是在同一台机器通信的两个进程的最佳途径?
-
19-08-2019 - |
题
什么是最好的(也许不是最好的 - 刚刚好)吗?在同一台机器通信的两个进程的方式,使用.NET
其实在应用这两个过程我的工作,甚至没有两个不同的程序;他们只是两个相同的EXE的实例。我想做一些像一个单身的应用程序,但有它每用户(指有多个用户的终端服务器或Citrix或App-V的服务器应该能够启动的应用程序自身的单拷贝)。如果另一个实例是由同一个用户运行,它应该只是委派任务已经运行的实例,然后退出。每个节目的用户只有一个实例应该运行。到目前为止,我已经做了(感谢StackOverflow的),可检测应用程序的实例是否已经在运行,使用互斥的部分。但我需要第二应用程序实例,以便能够将数据发送到所述第一应用程序实例。
我倾向于使用命名管道和WCF的NetNamedPipeBinding这一点,但如果你有更好的想法,我会很感激它。感谢:)
解决方案
我会去命名管道。
基本上,你需要每个用户的唯一终点。至于你的互斥,你可能会使用的用户名,找出命名管道使用的名称。这甚至可能会取代你的互斥体的使用:试图找出是否命名管道为这个特殊的已经存在,如果确实如此,这意味着你的第二个实例来运行
这是很难TCP端口映射到一个用户。
哦,对使用命名管道,实际上,我说:“远程处理命名管道”。
其他提示
命名管道通常是最好的,但也考虑MSMQ的火灾和忘记的场景,确保了长时间的消息传递。这真的取决于你的邮件大小,以及。因为你需要每个用户唯一的端口TCP会变得非常棘手。
IPC是我在过去的这个用过。它是supprisingly容易。 .Net远程的是一个很好的选择,但不幸的是它是一个受限制的选项becasue你不能例如使用它的CF。
下面是我用来执行进程间通信类的副本,可以在与一起选择一个互斥体,如果你想使用它,但它不是必需的。只要“pMappedMemoryName”和“pNamedEventName”在这两个过程是相同的,它应该只是罚款。我试图使它作为事件驱动越好。
只需使用戳方法写入数据,和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();
}
}
我希望这有助于。
.NET远程处理也可能是方便的。它的快速和容易实现。
您可以通过“本地\”的前缀名称设置一个互斥的,以“会话本地”的范围;阅读 MSDN 了解。这样,您就可以限制每个终端会话的流程实例(好吧,这不正是你问)。
的SendMessage / PostMessage的和GETMESSAGE是API的我喜欢这个
的SendMessage:结果 http://pinvoke.net/default.aspx/user32.SendMessage
PostMessage的:结果 http://pinvoke.net/default.aspx/user32.PostMessage
的GetMessage:结果 http://pinvoke.net/default.aspx/user32.GetMessage