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.
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.
** 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 **.
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
.
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 by
write 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.
,
read,
write,
remove`.[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