FIFO與管道幾乎相似,因此FIFO也是一個字節流,從FIFO讀取的順序也是與被寫入FIFO的順序一致,容量是也有限的,也是能夠確保寫入不超過PIPE_BUF字節的操做是原子的,FIFO的本質也是一個管道,但傳遞方向是能夠雙向的,它們二者之間的最大差異在於FIFO在文件系統中擁有一個名稱,而且打開方式與打開一個普通文件是同樣的(使用open),這樣就可以將FIFO用於非相關進程之間的通訊(如客戶端和服務器)。(不熟悉管道的能夠看個人另外一篇文章講述管道linux 進程間通訊之管道)linux
#include<sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);//return 0 on success,or -1 on error
複製代碼
readFd=open(pathname,O_RDONLY);//打開只讀方式
複製代碼
writeFd=open(pathname,O_WRONLY);//打開只寫方式
複製代碼
能夠確保每次寫入不超過PIPE_BUF字節的操做是原子的,當超過PIPE_BUF字節,內核會對消息進行拆分,那麼就有可能混淆與其餘寫者發送的消息,若是隻有一個寫者則不用擔憂混淆便可以忽略這個限制。bash
多個客戶端從FIFO中讀取數據時會相互競爭,這樣就可能會出某個客戶端讀取到其餘客戶端的響應消息。服務器
在單服務器、多客戶端應用程序中使用FIFO post
服務端程序核心ui
// 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 responses
if (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");
}
}
複製代碼
客戶端程序核心spa
//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");
}
複製代碼
當一個進程打開一個FIFO的一端時,若是FIFO的另外一端尚未被打開,則該進程會被阻塞。但有些時候阻塞並非指望的行爲,能夠經過調用open()時指定O_NONBLOCK3d
fd=open("fifopath",O_RDONLY|O_NONBLOCK);
if(fd==-1){
errExit("open");
}
複製代碼
O_NONBLOCK 標記不只會影響open()的語義,還會影響後續的read()和write()調用語義。code
能夠經過fcntl() 啓用或禁用打開着的文件的O_NONBLOCK狀態的標記。cdn
啓用標記server
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 flags
複製代碼
禁用標記
flags=fcntl(fd,F_GETFL);
flags&=~O_NONBLOCK; //disable O_NONBLOCK bit
fcntl(fd,F_SETFL,flags);
複製代碼
從一個包含p字節的管道或FIFO中讀取n字節的語義
向一個管道或FIFO寫入n字節的語義