1. An overview of the
The FIFO is almost similar to a pipe, so the FIFO is also a byte stream, and the order of reading from the FIFO is the same as the order of writing to the FIFO. The capacity is also limited, and the operation that can ensure that no more than PIPE_BUF bytes are written is atomic. The essence of the FIFO is also a pipe, but the direction of transmission can be bi-directional. The biggest difference between the two is that FIFO has a name in the file system and is opened in the same way as a normal file (using open), making it possible to use FIFO for communication between unrelated processes (such as clients and servers). (For those unfamiliar with pipes, see my article on pipes for Linux interprocess communication.)
2. Create a FIFO
#include<sys/stat.h>int mkfifo(const char *pathname,mode_t mode); //return 0 on success,or -1 on error
Copy the code
- The mode parameter specifies the permissions of the new FIFO, namely the file permissions (rw-rw—-).
- The mode parameter xor with the umask value in the process to specify the final permission value (so umask(0) is usually set).
3. Open the FIFO
- The FIFO is created successfully, and any process can open it, as long as it passes the normal file permission check that was originally set to mode.
readFd=open(pathname,O_RDONLY); // Enable read-only modeCopy the code
writeFd=open(pathname,O_WRONLY); // Open the write only modeCopy the code
- Opening a FIFO to read data (open() O_RDONLY flag) will block until another process opens THE FIFO to write data (open() O_WRONLY). Accordingly, opening one FIFO to write data will block until another process opens the FIFO to read data.
4. The only sensible way to use A FIFO is to have a read process and a write process at each end
-
The operations that ensure that no more than PIPE_BUF bytes are written at a time are atomic. When more than PIPE_BUF bytes are written, the kernel will split the message, and it is possible to confuse messages sent with other writers. If there is only one writer, this limitation can be ignored without worrying about confusion.
-
Multiple clients will compete to read data from the FIFO, which may result in a response message from one client to another.
-
Use FIFO in single-server, multi-client applications
Server program core
// we get the permissions we want
umask(0);
if(mkfifo(SERVER_FIFO,S_IRUSR|S_IWUSR|S_IWGRP)==-1&&errno! =EEXIST){ ERR_EXIT("mkfifo");
}
serveFd=open(SERVER_FIFO,O_RDONLY);
if(serveFd==-1){
ERR_EXIT("open");
}
for(;;) { //Read requests and send responsesif (read(serveFd, &req, sizeof(struct request)) ! = sizeof(struct request)) { errMsg("ERROR reading request; discarding\n");
continue;
}
//Open client FIFO (previously created by client)
snprintf(clientFifo,CLIENT_FIFO_NAME_LEN,CLIENT_FIFO_TEMPLATE,(long)req.pid);
clientFd=open(clientFifo,O_WRONLY);
if(clientFd==-1){
errMsg("open\n");
continue;
}
//send response and close FIFO
if(write(clientFd,&resp, sizeof(struct response))! = sizeof(struct response)){ errMsg("Error writing to FIFO");
}
if(close(clientFd)==-1){
errMsg("close"); }}Copy the code
Client program core
//create our FIFO (before sending request,to avoid a race)
umask(0);
snprintf(clientFifo,CLIENT_FIFO_NAME_LEN,CLIENT_FIFO_TEMPLATE,(long)getpid());
if(mkfifo(clientFifo,S_IRUSR|S_IWUSR|S_IWGRP)==-1&&errno! =EEXIST){ ERR_EXIT("mkfifo");
}
serverFd=open(SERVER_FIFO,O_WRONLY);
if(serverFd==-1){
ERR_EXIT("open");
}
if(write(serverFd, &req, sizeof(struct request)) ! = sizeof(struct request)) { ERR_EXIT("write");
}
//open our FIFO,read and display response
clientFd=open(clientFifo,O_RDONLY);
if(clientFd==-1){
ERR_EXIT("open");
}
if(read(clientFd,&resp, sizeof(struct response))! = sizeof(response)){ ERR_EXIT("read");
}
if(close(clientFd)==-1){
ERR_EXIT("close");
}
Copy the code
5. Non-blocking I/O
When a process opens one end of a FIFO, the process is blocked if the other end of the FIFO is not already open. But sometimes blocking is not the desired behavior, and you can specify O_NONBLOCK when calling open()
fd=open("fifopath",O_RDONLY|O_NONBLOCK);
if(fd==-1){
errExit("open");
}
Copy the code
5.1 Using the O_NONBLOCK flag when opening a FIFO serves two purposes
- It allows a single process to open both sides of a FIFO. The process first specifies the O_NONBLOCK flag when the FIFO is turned on to read data, and then the FIFO is turned on to write data.
- It prevents deadlocks between processes that open two FIFOs.
5.2 Non-blocking Read () and write()
-
The O_NONBLOCK tag affects not only the semantics of open(), but also the semantics of subsequent read() and write() calls.
-
Flags for the O_NONBLOCK state of open files can be enabled or disabled by FCNTL ().
Enable the tag
int flags; flags=fcntl(fd,F_GETFL); //Fetch open files status flags flags|=O_NONBLOCK; // Enable O_NONBLOCK bit fcntl(fd,F_SETFL,flags); // Update open files status flagsCopy the code
Disable the tag
flags=fcntl(fd,F_GETFL); Flags & = ~ O_NONBLOCK; //disable O_NONBLOCK bit
fcntl(fd,F_SETFL,flags);
Copy the code
6. Read and write semantics in pipes and FIFO
Read n bytes of semantics from a pipe or FIFO containing P bytes
Write n bytes of semantics to a pipe or FIFO