MemoryMappedFileIPC 1.0.0
See the version list below for details.
dotnet add package MemoryMappedFileIPC --version 1.0.0
NuGet\Install-Package MemoryMappedFileIPC -Version 1.0.0
<PackageReference Include="MemoryMappedFileIPC" Version="1.0.0" />
<PackageVersion Include="MemoryMappedFileIPC" Version="1.0.0" />
<PackageReference Include="MemoryMappedFileIPC" />
paket add MemoryMappedFileIPC --version 1.0.0
#r "nuget: MemoryMappedFileIPC, 1.0.0"
#:package MemoryMappedFileIPC@1.0.0
#addin nuget:?package=MemoryMappedFileIPC&version=1.0.0
#tool nuget:?package=MemoryMappedFileIPC&version=1.0.0
MemoryMappedFileIPC
Pure c# IPC library using a memory mapped file (shared memory).
Pub/sub interface, compatible with most .NET versions. Only works on Windows.
What is it?
Memory mapped files, also known as shared memory, allow for efficient communication between processes. They are much faster than websockets, named pipes, and TCP or UDP.
However, the C# interface to memory mapped files is low-level. In particular, implementing pub-sub for multiple publishers and subscribers is non-trivial.
This is a higher-level, thread-safe wrapper that lets you do robust IPC easily.
How to use?
Setup
First, pick a directory that'll hold the list of existing connections. Each alive connection will be a json file in this directory.
A simple option is something like
string serverDirectory =
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"YourApplication",
"IPCConnections",
"Servers"
);
Next, select a channel name. Only publishers and subscribers that share this label will be able to communicate.
string channelName = "testChannel";
Sending messages
Create an IpcPublisher:
IpcPublisher publisher = new IpcPublisher(channelName, serverDirectory);
You can then call
byte[] byteArray = ...; // make your bytes however you want
publisher.Publish(byteArray);
to send some bytes.
Make sure to call
publisher.Dispose()
once you are done using it.
If you want to know when our publisher has connected to any subscriber, you can use
publisher.connectEvent.WaitOne()
and for disconnections from all subscribers, you can use
publisher.disconnectEvent.WaitOne()
Alternatively, just look for when
publisher.NumActiveConnections()
is greater than zero.
Recieving messages
Create an IpcSubscriber:
IpcSubscriber subscriber = new IpcSubscriber(channelName, serverDirectory);
Now you can subscribe to the message event:
subscriber.RecievedBytes += (bytes) =>
{
// process your bytes
}
Make sure to call
subscriber.Dispose()
once you are done using it.
there is a connectEvent, disconnectEvent, and NumActiveConnections() available, just like with the publisher.
Bidirectional communication?
Just make each side have both a publisher and a subscriber. Publishers will only connect to subscribers with a different process id.
Implementation Details
Every pair of subscriber-publisher has it's own memory mapped file. This simplifies things and allows each connection to transfer data at it's own pace.
Connections
Subscribers will always have one open connection (not connected yet), to ensure that there's always room for another publisher to connect to them.
One subscriber recieving messages from multiple publishers is supported.
One publisher sending to multiple subscribers is supported.
All subscribers will recieve all messages sent by all publishers with the same channelName.
Every publisher will create it's own .json file in the directory provided. This allows the subscribers to just scan this directory occasionally to find new connections.
Ping
Every sub/pub pair actually has two connections:
- a "data" connection which is used to send data
- a "ping"/keepalive connection which is used to check if the connection is still alive
the ping connection will send a ping every 1 second, you can adjust this by passing in the millisBetweenPing parameter.
But make sure subscriber and publisher have the same value for millisBetweenPing or they will disconnect.
These are seperate connections to allow for the data thread to take as long as you want processing the data.
Syncronization
I use \\Global shared event wait handles (see MemoryMappedFileServer.cs).
This is a Windows-only feature that lets me have cross process shared wait handles to let me know when reading and writing have completed.
This is the only part of this library that is Windows-specific, if someone can figure out a non-windows shared event wait handle implemention I would be happy to accept a PR.
Dispose/Async
This library is fully thread-safe.
Also, I use only async operations which all recieve a Cancellation token. This ensures that calling Dispose() will immediately terminate all threads and dispose of all resources properly.
Alternatives
https://github.com/cloudtoid/interprocess seems good, however named semaphores weren't supported on the version of .net I wanted to use, which is why this library exists.
Named pipes are an alternative to shared memory. However they are slower, and the async read/write methods aren't supported in the version of mono I was using (Resonite).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET Framework | net472 is compatible. net48 was computed. net481 was computed. |
-
.NETFramework 4.7.2
- Newtonsoft.Json (>= 13.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2.0 | 289 | 3/7/2025 |
| 1.1.6 | 167 | 2/26/2025 |
| 1.1.5 | 142 | 2/26/2025 |
| 1.1.4 | 145 | 2/26/2025 |
| 1.1.2 | 164 | 2/25/2025 |
| 1.1.1 | 159 | 2/25/2025 |
| 1.0.9 | 162 | 2/25/2025 |
| 1.0.7 | 148 | 2/6/2025 |
| 1.0.6 | 160 | 2/5/2025 |
| 1.0.5 | 170 | 2/5/2025 |
| 1.0.4 | 157 | 2/3/2025 |
| 1.0.3 | 159 | 2/2/2025 |
| 1.0.2 | 164 | 2/2/2025 |
| 1.0.0 | 159 | 1/27/2025 |