
At the beginning of my work as a junior developer, I had to deal with such an incomprehensible for me at that time concept like Inter-Process Communication. It was a complete wildness for a novice programmer, who, within the framework of the logic of one application, was guided with great difficulty. It is worth mentioning that the project is written in Delphi, and the IPC mechanism itself is implemented using File Mapping and Windows Messages.
What is surprising, I learned how this whole system works from the inside, after almost a year, when I had to tinker a little with it. And only then I finally realized how high-level its implementation was, and the API was convenient. Who is interested in the implementation of something similar to the above system under C # - please under the cat.
Since in my free time I study the .NET Framework, I was interested in how easily / conveniently implemented IPC on .NET. To my own disappointment, I realized that the functionality from the box is significantly inferior to the convenience and simplicity of the handicraft Delphi system. Here you can make a good holivar of this kind, relying on the fact that .NET is focused on abstracting from the data transfer channel and allows you to fumble objects equally well across the network and between processes. But since the topic of the article is IPC, I will ask not to do this.
A little introduction. I was not able to fully understand all the tricks of IPC on .NET, but having
smoked manuals after reading the thematic articles, I realized that it’s realistic to use the following options:
1. com,
2. File Mapping,
3. IPC Channels.
Since the implementation using COM or File Mapping will differ little from analogs in other languages, the choice clearly fell on the built-in IPC mechanism for .NET.
After trying to write a little bit of a functional application, I realized that even the transmission of a simple string using it requires unnecessary gestures on both applications, both in the sender and in the receiver. As a result, for the object balls between processes it is necessary to do something like:
')
Server:
IpcChannel serverChannel = new IpcChannel("MyServerChannel"); ChannelServices.RegisterChannel(serverChannel); RemotingConfiguration.RegisterWellKnownServiceType( typeof(IPCChannelRemoting.MyRemoteObject), "SharedObj", WellKnownObjectMode.SingleCall);
Customer:
IpcChannel clientChanel = new IpcChannel("myClient"); ChannelServices.RegisterChannel(clientChanel); ISharedObj obj = (Remoteable.ISharedAssemblyInterface)Activator.GetObject( typeof(Remoteable.ISharedAssemblyInterface), "ipc://MyServerChannel/SharedObj ");
But what if the data exchange is to be used everywhere in the application? In this case, you will have to duplicate the code throughout the descriptions above and specify the rules for creating URIs for shared objects. And if it is necessary not only to request data from another process, but also to subscribe to receive some kind of signal / message? You can make a thread / timer that loops in a validation loop or use WaitForSingleObject / EventWaitHandle. In general, there is no longer do without personally created architecture.
From previous experience in developing an application that makes extensive use of IPC mechanisms, it is very convenient to use the following approach:
- there are three main entities: the sender, the recipient and the message;
- each recipient and sender has their own unique ID, which is the sending of messages. They can be tied to the PID of the application, the window handle or any well-known identifier that is known to both parties;
- a message is an abstract concept that can contain fields of any * type, be synchronous or asynchronous. Applications that exchange these messages should be aware of specific classes that are descendants of basic messages. The difference between synchronous and asynchronous messages is that in a synchronous message you can put the result of the request, if necessary, and it will be available to the sender immediately after processing the message (by returning the stack from calling the sending method).
As a result, using the resulting system, sending data between processes is reduced to
- create sender objects and messages,
- sending messages using the sender,
- its processing in the process of the recipient.
using (BaseIPCDispatcher dispatcher = new BaseIPCDispatcher(slaveReceaverGUID)) { TestAsyncComplexMessage testMessage = new TestAsyncComplexMessage (ReceaverID, null); dispatcher.Dispatch(testMessage); }
Subscribing to a message in another, or the same process:
… Receiver.OnReceaveIPCMessage += OnReceaveMessage; … private void OnReceaveMessage(object sender, ReceaveMessageEventArgs e) { TestAsyncComplexMessage testAsyncMessage = e.Message as TestAsyncComplexMessage; if (testAsyncMessage != null) {
IMHO, it turned out a little more obvious, flexible and readable. The code is covered in functional tests using the Master / Slave architecture.
Who wants to get acquainted - the result is on GitHub
github.com/perevernihata/SimpleIPCCommSystemZY I understand that maybe I unknowingly invented my bike with square wheels, but it's really damn interesting to do! Constructive criticism is welcome.
* (Serializable for asynchronous messages).