Reading/Writing from Named Pipes Under Mono/Linux

Reading/writing from named pipes under mono/Linux

You'll need to open separate readers and writers; for some reason, Mono treats FIFOs as if they are seekable (it's a bug), even though they aren't.

Do Named Pipes Clear Read Data

Data from pipes, named or otherwise, is consumed when read. If you want to write persistent data, use a regular file.

Note that the pipe will grow if data isn't read, up to a size limit defined by system configuration.

Named pipe written content life

It'll not save anything. When you read/write something to the named pipe, it the process will be blocked unless some other process writes/reads from the same named pipe.

The file stays in the file-system. But the content goes away when reading/writing finishes.

From linux manual,

Once you have created a FIFO special file in this way, any process
can open it for reading or writing, in the same way as an ordinary file.
However, it has to be open at both ends simultaneously before you can
proceed to do any input or output operations on it
. Opening a FIFO for
reading normally blocks until some other process opens the same FIFO for
writing, and vice versa.

How to create named pipe (mkfifo) with .net6 in linux?

The only thing I found how to create a named pipe (mkfifo) from .net6 so far is with Mono:

https://github.com/dotnet/runtime/issues/24390#issuecomment-384650120

You can use the Mono.Posix.NetStandard library on .NET Core to get
access to the mkfifo POSIX command. This will allow your program to
read/write to a FIFO/Unix named pipe.

https://github.com/mono/mono/blob/47187bbc9b552f6ca5b2d80a2be6c7395b40da9e/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs#L4013-L4017

To write in a named pipe, you can simply use FileStream like this:

using FileStream fs = File.OpenWrite(namedPipePath);
fs.WriteByte(134);

Note, that this call will block until someone else will start reading it (another process, or whoever).

In my case it was enough to write into the pipe without creating it in .net6 because I could create it terminal via mkfifo.

Edit

I found a solution to create a pipe. Simply using the Process class:

ProcessStartInfo startInfo = new ProcessStartInfo("mkfifo");
startInfo.Arguments = "pathtonamedpipe";
Process.Start(startInfo);

Can I open a named pipe on Linux for non-blocked writing in Python?

From man 7 fifo:

A process can open a FIFO in nonblocking mode. In this case, opening for read-only will succeed even if no-one has opened on the write side yet, opening for write-only will fail with ENXIO (no such device or address) unless the other end has already been opened.

So the first solution is opening FIFO with O_NONBLOCK. In this case you can check errno: if it is equal to ENXIO, then you can try opening FIFO later.

import errno
import posix

try:
posix.open('fifo', posix.O_WRONLY | posix.O_NONBLOCK)
except OSError as ex:
if ex.errno == errno.ENXIO:
pass # try later

The other possible way is opening FIFO with O_RDWR flag. It will not block in this case. Other process can open it with O_RDONLY without problem.

import posix
posix.open('fifo', posix.O_RDWR)

Do I need to flush named pipes?

Pipes are not buffered, no need to flush.

I'd actually put that the other way around: for most intents and purposes, pipes are nothing but buffer. It is not meaningful to flush them because there is no underlying device to receive the data.

Moreover, although POSIX does not explicitly forbid additional buffering of pipe I/O, it does place sufficient behavioral requirements that I don't think there's any way to determine from observation whether such buffering occurs, except possibly by whether fsync() succeeds. In other words, even if there were extra buffering, it should not be necessary to fsync() a pipe end.

But in a ordinary file, I
would fflush (or fsync) the file descriptor.

Well no, you would not fflush() a file descriptor. fflush() operates on streams, represented by FILE objects, not on file descriptors. This is a crucial distinction, because most streams are buffered at the C library level, independent of the nature of the file underneath. It is this library-level buffer that fflush() interacts with. You can control the library-level buffering mode of a stream via the setvbuf() function.

On those systems that provide it, fsync() operates at a different, lower level. It instructs the OS to ensure that all data previously written to the specified file descriptor has been delivered to the underlying storage device. In other words, it flushes OS-level buffers.

Note well that you can wrap a stream around a pipe-end file descriptor via the fdopen() function. That doesn't make the pipe require flushing any more than it did before, but the stream will be buffered by default, so flushing will be relevant to it.

Note, too, that some storage devices perform their own buffering, so that even after the data have been handed off to a storage device, it is not certain that they are immediately persistent.

How about named pipe?

The discussion above about stream I/O vs. POSIX descriptor-based I/O applies here, too. If you access a named pipe via a stream, then its interaction with fflush() will depend on the buffering of that stream.

But I suppose your question is more about os-level buffering and flushing. POSIX does not appear to say much concrete, but since you tag [linux] and refer to a Linux manual page in your question, I offer this in response:

The only difference between pipes and FIFOs is the manner in which
they are created and opened. Once these tasks have been accomplished,
I/O on pipes and FIFOs has exactly the same semantics.

(Linux pipe(7) manual page.)

Writing string to pipe

Normally a FIFO has to be open at both ends simultaneously before either side can proceed. Since you didn't mention anything about a reader, the most likely answer is that you haven't got one, or you haven't set it up yet. Once you do, the open will be allowed to proceed.



Related Topics



Leave a reply



Submit