Reading data from a socket directly into a Memory Mapped File

552 Views Asked by At

I'm trying to create a .NET Core application and am getting a little stuck on IPC.

I have data coming in (let's say, from a socket, or a file, some sort of streaming interface), via executable 1. Now, I want this data to be read by executable 2. So, I've created a MMF, where executable 1 writes data, and executable 2 reads data. All is well.

However, I would really like to skip the "copy" step here. If I have a message coming in via a socket, I need to read the message (ergo; store it in some byte array), and then copy it to the appropriate Memory Mapped File.

Is there a way (especially now, with the new Memory, Span etc) to have them use the same memory?

This code almost seems to work, but not completely:

const int bufferSize = 1024;

var mappedFile = MemoryMappedFile.CreateNew("IPCFile", bufferSize);
var fileAccessor = mappedFile.CreateViewAccessor(0, bufferSize, MemoryMappedFileAccess.ReadWrite);

// THere now exists a region of byte[] * bufferSize somewhere. I want to write to that.

byte[] bufferMem = new byte[bufferSize];

// I know the memory address where this area is, and I know the size of it:
unsafe
{
    byte* startOfRegion = (byte*)0;
    fileAccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref startOfRegion);
    // But how do I "assign" this region to the managed object?

    // This throws "System.MissingMethodException: 'No parameterless constructor defined for type 'System.Byte[]'."
    //bufferMem = Marshal.PtrToStructure<byte[]>(new IntPtr(startOfRegion));

    // This almost looks like it works, but bufferMem remains null. Does not give any errors though.
    bufferMem = Unsafe.AsRef<byte[]>(startOfRegion);
}

// For a shorter example, just using a file stream
var incomingData = File.OpenRead(@"C:\Temp\plaatje.png");

// Pass in the "reserved" memory region. But StreamPipeReaderOptions wants a MemoryPool<byte>, not a byte[].
// How would I cast that? MemoryPool is abstract, so can't even be instantiated
var reader = PipeReader.Create(incomingData, new StreamPipeReaderOptions(bufferMem));
ReadResult readResult;

// Actually read data
while (true)
{
    readResult = await reader.ReadAsync();
    if (readResult.IsCompleted || readResult.IsCanceled)
        break;

    reader.AdvanceTo(readResult.Buffer.Start, readResult.Buffer.End);
}

// Now signal the other process to read the contents of the MMF and continue

This question seems to ask a similar thing, but does not have an answer, and is from 2013.

0

There are 0 best solutions below