管道没有名字,因此它们最大的劣势在于只能用于有一个祖先进程的各个进程之间。我们无法在无亲缘关系的两个进程间创建一个管道并将它用作IPC通道(不考虑文件描述符)。
FIFO指先进先出,UNIX中的FIFO类似管道。它是一个单向的(半双工)的数据流。不同于管道的是,每个FIFO有一个路径名与之关联,从而允许无亲缘关系的进程访问同一个FIFO,FIFO也成为有名管道。
FIFO由mkfifo函数创建。
int mkfifo(const char* pathname,mode_t mode)
mkfifo函数已隐含指定O_CREAT | O_EXCL,也就是说,它要么创建一个新的FIFO,要么返回一个EEXIST错误。如果不希望创建一个新的FIFO,那么就改为调用open而不是mkfifo。要打开一个已存在的FIFO或创建一个新的FIFO,应先调用mkfifo,再检查它是否返回EEXIST错误,若返回该错误则改为调用open。
函数说明:
mkfifo ()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此 umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开 FIFO文件时,O_NONBLOCK旗标会有影响
现在重新编写之前在管道那节博客中的客户端服务器程序,这次改用两个FIFO代替两个管道,客户端向服务器发出文件的路径,服务器返回文件的内容。
其布局如图:
首先给出main函数:
#include"uitil.h"
int main(int argc,char*argv[])
{
int pipe1[2],pipe2[2];
pid_t pid;
int res1;
int res2;
//创建管道
res1 = pipe(pipe1);
if(res1 == -1){
cout << "pipe error." << endl;
exit(1);
}
res2 = pipe(pipe2);
if(res2 == -1){
cout << "pipe error." << endl;
exit(1);
}
//fork用于创建一个子进程
pid = fork();
if(pid == 0){
cout << "child." << endl;
//child
//子进程从管道1中读数据,写到管道2中
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0],pipe2[1]);
exit(0);
}else if(pid > 0){
cout << "parent." << endl;
//father
//父进程从管道2中读数据,写到管道1中
close(pipe1[0]);
close(pipe2[1]);
client(pipe2[0],pipe1[1]);
waitpid(pid,NULL,0);
exit(0);
}else{
cout << "fork error." << endl;
exit(1);
}
return 0;
}
客户端程序:
void client(int readfd,int writefd)
{
size_t len;
ssize_t n;
char buff[MAXLINE];
//char *fgets(char*buf,int bufsize,FILE* stream)
//参数
// *buf:字符型指针,指向用来存储所的数据的地址
// bufsize:整型数据,指明存储数据的大小
// *stream:文件结构体指针,将要读取的文件流
//返回值:
// 1.成功,则返回第一个参数buf
// 2.在读字符时遇到end-of-file,则eof指示器被设置,
// 如果还没读入任何字符就遇到这种情况,则buf保持原来的内容,返回NULL
// 3.如果发生读入错误,error指示器被设置,返回NULL,buf的值可能被改变
//stdin代表输入的路径名
fgets(buff,MAXLINE,stdin);
len = strlen(buff);
if(buff[len - 1] == '\n')
len--;
//将路径名写入到管道1
write(writefd,buff,len);
//客户端从管道2中读取文件的内容
while((n = read(readfd,buff,MAXLINE)) > 0){
write(STDOUT_FILENO,buff,n);
}
}
服务器程序:
void server(int readfd,int writefd)
{
int fd;
ssize_t n;
char buff[MAXLINE + 1];
// ssize_t read(int fd,void* buf,size_t nbytes)
// 把参数fd所指的文件的nbyte个字节读到buf指针所指的内存,
// 若nbytes为0,则read()不会有作用并返回0;
// 返回值为实际读取到的字节数,返回0表示已到达文件尾或无可取的数据,错误返回-1
// 并将根据不同的错误原因适当的设置错误码
//服务器从管道1中读取路径名
n = read(readfd,buff,MAXLINE);
if(n == 0){
cout << "end_of_file while reading pathname." << endl;
exit(1);
}
buff[n] = '\0';
//以只读方式打开文件
fd = open(buff,O_RDONLY);
if(fd < 0){
snprintf(buff + n,sizeof(buff) - n,":cant't open ,%s\n",strerror(errno));
n = strlen(buff);
write(writefd,buff,n);
}else{
//当服务器打开文件成功时,将文件的内容写入到管道2
while((n = read(fd,buff,MAXLINE)) > 0){
write(writefd,buff,n);
}
//关闭文件
close(fd);
}
}
头文件uitil.h
#pragma once
#include<iostream>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#define MAXLINE 4096
using namespace std;
其客户端程序和服务器的程序基本没变,只是在main函数中有变动!!!
其执行结果:
程序执行结果是一样的。。。。