Named Pipes
682 words.
At work we have a Windows Service that runs continuously, doing important stuff. I wanted to write a lightweight WinForm monitor that I could run independently from the service (on the same machine) to watch what it’s doing in real time, without the hassle of continually re-loading a plain text log file. Performance Monitor was not sufficient because I wanted actual text messages.
I needed to investigate Inter-Process Communication (IPC).
Back in the good old days of Amiga programming, this kind of thing was pretty easy. Everybody could access everyone else’s memory, so we could recklessly pass data pointers back and forth between processes at will. We just needed a semaphore to make sure two processes didn’t write to the same memory at the same time. No big deal. (If we were feeling particularly reckless, we wouldn’t even bother with the semaphores.)
In Windows, though, it’s more complicated. Each process has its own independent memory space. Or something. (My understanding of the underlying kernal is foggy.) Anyway, the bottom line is that you can’t just pass pointers from from one process to another. You have to implement some kind of IPC mechanism.
There are numerous ways of doing this in Windows. I’ll enumerate some of them below.
- Clipboard. I don’t know why anyone would even try to do IPC with the Clipboard.
- WM_COPYDATA. I’m not using Windows messages.
- COM objects. Possible issues installing on the server, and using old technology is not appealing.
- WinSock. A good idea, but for this case I don’t trust my network administrators not to block TCP traffic somehow, even locally on the server. I’m not sure how, but I know they’d find a way to mess it up.
- Web Services. Slow, and the same issues with installation and network administrators.
- Remote Procedure Calls. I haven’t explored this, but it sounds like overkill for my requirements.
- Shared Memory. Sounds intriguing, but I haven’t explored this.
- Mailslot. Untried, but it sounds very similar to named pipes below.
- Named Pipes. Perfect?
As you might guess, my experimentation so far is focusing on Named Pipes. What I’m hoping for is something like the old Amiga Exec message queues. I want my Windows Service to push messages into a queue and send them to the receiver, without interrupting the work of the service at all.
Named pipes are based around a file stream model. Basically you’re opening a file between two processes; what one process writes, the other process reads. Unfortunately one end can’t read from the pipe until the other end finishes writing and closes it, and vice versa. At least, that’s my experience so far.
My implementation has the Windows Service creating a message queue thread. The service sends messages to the thread and they are queued. Periodically, the thread attempts to open a named pipe client and write out all the messages queued up. (If the pipe is unavailable, meaning that the receiving monitor program isn’t currently running, the messages are discarded.)
On the Monitor program side, a named pipe server is created, and the program continually waits for connections. When a connection is made, messages are read from the pipe and displayed.
By the way, in my case “messages” are simple text messages and are packaged in a simplified XML-style format. One or more messages can be sent through each pipe connection.
So far this implemention is working adequately. There is one drawback that I’m still trying to resolve: The pipe server thread blocks while waiting for a connection. Unfortunately, sometimes it doesn’t stop blocking even if it’s aborted by a Thread.Abort. Killing the Monitor process from the Task Manager is not my ideal way to exit a program.
Incidentally, I had to write .NET wrappers for the named pipe functions, since there isn’t any support for them in the .NET Framework. I guess Microsoft wants everyone to use Remoting and Web Services. Anyway, I was heavily influenced by a Code Project article by Ivan L, which was in turn based on code from Jay Hawkins.
UPDATE: .NET 3.5 added support for Named Pipes through the System.IO.Pipes namespace.
Sorry, new comments are disabled on older posts. This helps reduce spam. Active commenting almost always occurs within a day or two of new posts.