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字节的语义