[LINUX] How to use blocking / non-blocking FIFO (named pipe)

I'm a beginner who recently started system programming. I am writing an article to fix my knowledge, so if you have any mistakes or advice, it would be very helpful if you could point them out in the comments.

Overview

This article explains the FIFO and how to use it with code examples. The programs appearing in this article have been confirmed to work in the following environments.

Ubuntu 18.04.4 LTS (Bionic Beaver)
gcc version 9.2.1

In addition, I will leave the particularly detailed explanations (detailed errors and their countermeasures, etc.) such as the API introduced in this article to the target document, and point out the minimum necessary points and addiction points that I needed to use FIFO. I will focus on the explanation.

What is FIFO

** FIFO ** is a type of interprocess communication, also called named pipe **, and has been extended so that anonymous pipes, which could only be used between processes with a common ancestor, can be used as a means of communication between different processes. Thing.

FIFO is a kind of file in Unix-like OS, and it can be operated like a normal file **.

How to make a FIFO

The FIFO is basically created by specifying the path with mkfifo or mkfifoat.

mkfifo


  int ret = mkfifo("test", 0666);
  int (ret == -1) {
    perror("mkfifo");
  }

mkfifoat creates a FIFO based on the specified file descriptor.

mkfifoat


  int fd, ret;
  const char* home_path = getenv("HOME"); //Get the HOME path from an environment variable
  
  fd = open(home_path, O_RDONLY); //Get fd of HOMEDir
  if (fd == -1) {
    perror("open");
    exit(0);
  }
  
  ret = mkfifoat(fd, "test", 0666); //Create FIFO based on HOME
  if (ret == -1) {
    perror("mkfifo");
  }

Since FIFO is a kind of file, its existence can be confirmed by ls.

Also, if a FIFO with the same name already exists, ʻerrno is set to ʻEEXIST.

How to use FIFO

FIFOs use a file system, so you can use ʻopen, write, and read` to manipulate files. (However, the place where the data is written is the buffer in the kernel.) open Just like opening a file, specify the path to the FIFO and open it.

open


  #include <sys/fcntl.h>

  int fd1 = open("test", O_RDONLY); //Read Only
  int fd2 = open("test", O_WRONLY); //Write Only
  int fd3 = open("test", O_RDWR); //Both reading and writing are possible

The FIFO cannot pass data until both ends are opened (= open is blocked).

This specification is inconvenient because the FIFO cannot be opened until the server accepts the communication from the client when communicating between the server and the client using the FIFO. Therefore, you can open the FIFO non-blocking by specifying ʻO_NONBLOCK of ʻopen`.

nonblocking


  #include <sys/fcntl.h>

  int fd_nb1 = open("test", O_RDONLY | O_NONBLOCK); //mode is specified by OR
  int fd_nb2 = open("test", O_RDWR | O_NONBLOCK);

As a caveat when specifying NONBLOCK, when opening a FIFO in write mode, ʻENXIO (no such device or address) is returned even if one is open. That's why we're using ʻO_RDWR instead of ʻO_WRONLY` (although POSIX doesn't have O_RDWR rules, so it can only be used on Linux and should be ported with caution).

read You can read the data from the beginning of the FIFO by the specified number of bytes using the file descriptor when the FIFO is ʻopen`.

read(Blocking)


  //An example of read
  struct Packet {
    int data1;
    double data2;
  };

  void* buf = malloc(sizeof(Packet));
  int len = read(fd, buf, sizeof(Packet));
  
  Packet p = reinterpret_cast<Packet*>(buf);

Also, for non-blocking FIFOs, if blocked by read, ʻerrno is set to ʻEAGAIN and read returns -1.

read(NonBlocking)


  int len = read(fd, buf, SIZE);
  if (len < 0) {
    if (errno == EAGAIN) {
      fprintf(stderr, "avoid blocking\n");
    } else {
      perror("read");
    }
  } else if (len == 0) {
    printf("EOF\n"); // len ==When it is 0, it means that the entire contents of the pipe are being read.
  }
  
  // len >I read the data for len bytes at 0.

Also, when I experimented with the return value of read with FIFO by myself

Number of processes that opened the pipe in write mode return value of read
0 0 (EOF)
1 -1 (EAGAIN)or number of bytes read

The result was that.

write You can write the specified bytes to the FIFO in the same way as read.

write(Blocking)


  //An example of write
  struct Packet {
    int data1;
    double data2;
  }

  Packet p {10, 2.2};
  int len = write(fd, &p, sizeof(Packet));

For non-blocking FIFOs, ʻEAGAINis set when blocked bywrite as well as read`.

remove The FIFO must be explicitly removed.

remove


  int ret = remove("test");
  if (ret == -1) {
    perror("remove");
  }

I'm using remove to remove it, please let me know if there is another good way.

Summary

References / Sites

[Wikipedia Named Pipe](https://ja.wikipedia.org/wiki/%E3%83%91%E3%82%A4%E3%83%97_(%E3%82%B3%E3%83%B3) % E3% 83% 94% E3% 83% A5% E3% 83% BC% E3% 82% BF)) FIFO (Japanese translation of FIFO7) FIFO(7) Detailed UNIX Programming 3rd Edition

Recommended Posts

How to use blocking / non-blocking FIFO (named pipe)
How to use xml.etree.ElementTree
How to use Python-shell
How to use tf.data
How to use virtualenv
How to use Seaboan
How to use image-match
How to use shogun
How to use Virtualenv
How to use numpy.vectorize
How to use pytest_report_header
How to use partial
How to use Bio.Phylo
How to use SymPy
How to use x-means
How to use WikiExtractor.py
How to use IPython
How to use virtualenv
How to use Matplotlib
How to use iptables
How to use numpy
How to use TokyoTechFes2015
How to use venv
How to use dictionary {}
How to use Pyenv
How to use list []
How to use python-kabusapi
How to use OptParse
How to use return
How to use dotenv
How to use pyenv-virtualenv
How to use Go.mod
How to use imutils
How to use import
How to use Qt Designer
How to use search sorted
python3: How to use bottle (2)
Understand how to use django-filter
How to use the generator
[Python] How to use list 1
How to use FastAPI ③ OpenAPI
How to use Python argparse
How to use IPython Notebook
How to use Pandas Rolling
[Note] How to use virtualenv
How to use redis-py Dictionaries
Python: How to use pydub
[Python] How to use checkio
[Go] How to use "... (3 periods)"
How to use Django's GeoIp2
[Python] How to use input ()
How to use the decorator
[Introduction] How to use open3d
How to use Python lambda
How to use Jupyter Notebook
[Python] How to use virtualenv
python3: How to use bottle (3)
python3: How to use bottle
How to use Google Colaboratory
How to use Python bytes
How to use the zip function