MemoryMappedFileIPC 1.1.4

There is a newer version of this package available.
See the version list below for details.
dotnet add package MemoryMappedFileIPC --version 1.1.4
                    
NuGet\Install-Package MemoryMappedFileIPC -Version 1.1.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MemoryMappedFileIPC" Version="1.1.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MemoryMappedFileIPC" Version="1.1.4" />
                    
Directory.Packages.props
<PackageReference Include="MemoryMappedFileIPC" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MemoryMappedFileIPC --version 1.1.4
                    
#r "nuget: MemoryMappedFileIPC, 1.1.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MemoryMappedFileIPC@1.1.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MemoryMappedFileIPC&version=1.1.4
                    
Install as a Cake Addin
#tool nuget:?package=MemoryMappedFileIPC&version=1.1.4
                    
Install as a Cake Tool

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.

Because there could be multiple publishers and subscribers, sending multiple byte arrays in sequence might be non-trivial.

To address this (and to avoid needing to copy to one big byte array), it is also supported to do

byte[][] arrayOfByteArrays = ...; // make your bytes however you want
publisher.Publish(arrayOfByteArrays);

Once you are done with publisher, make sure to call

publisher.Dispose()

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 += (byte[][] bytes) =>
{
	// process your bytes
	// if you just sent one byte array above instead of a list, it'll be bytes[0]
}

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.

https://github.com/justinstenning/SharedMemory/ is a great alternative, however it doesn't support any number of publishers and subscribers on the same channel.

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 Compatible and additional computed target framework versions.
.NET Framework net472 is compatible.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.7.2

    • No dependencies.

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