管道和FIFO

pipe

子进程从终端读取一个文件名, 通过管道将文件名传递给父进程
父进程收到文件名后, 读取文件内容并通过管道传递给子进程
子进程接收到文件内容并输出到终端

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <sys/wait.h>
 
#define MAXLINE 4096
void err_quit(char *fmt,...){
    int errno_save;    
    errno_save=errno;

    va_list list;
    va_start(list,fmt);
    vfprintf(stderr,fmt,list);
    if(errno != 0)
        fprintf(stderr," :%s",strerror(errno_save));
    va_end(list);
    exit(1);
}
void Pipe(int *fds){
    if(pipe(fds)<0)
        err_quit("pipe error");
}
void Close(int fd){
    if(close(fd)<0)
        err_quit("close error");
}
pid_t Waitpid(pid_t pid,int *statloc,int option){
    pid_t retpid=waitpid(pid,statloc,option);
    if(retpid == -1)
        err_quit("waipid error");
    return retpid;
}
char *Fgets(char *buf,int n,FILE *fp){
    char *rptr=fgets(buf,n,fp);
    if(rptr == NULL && ferror(fp))
        err_quit("fgets error");
    return rptr;
}
ssize_t Read(int fd,void *buf,size_t nbytes){
    ssize_t nread=read(fd,buf,nbytes);
    if(nread == -1)
        err_quit("read error");
    return nread;
}
void Write(int fd,void *buf,size_t nbytes){
    if(write(fd,buf,nbytes) != nbytes)
        err_quit("write error");
}
 
 
void client(int,int), server(int,int);
int main(int argc, char *argv[]){
    int pipe1[2],pipe2[2];
    pid_t childpid;
 
    Pipe(pipe1);
    Pipe(pipe2);
 
    if((childpid=fork())<0)
        err_quit("fork error");
    else if(childpid == 0){
        Close(pipe1[1]);
        Close(pipe2[0]);
 
        server(pipe1[0],pipe2[1]);
    }else{
        Close(pipe1[0]);
        Close(pipe2[1]);
 
        client(pipe2[0],pipe1[1]);
        Waitpid(childpid,NULL,0);
    }
    exit(0);
} 
 
void client(int readfd,int writefd){
    size_t len;
    ssize_t n;
    char buf[MAXLINE];
 
    Fgets(buf,MAXLINE,stdin);
    len=strlen(buf);
    if(buf[len-1] == '
')
        len--;
    Write(writefd,buf,len);
 
    while((n=Read(readfd,buf,MAXLINE))>0)
        Write(STDOUT_FILENO,buf,n);
}
void server(int readfd,int writefd){
    int fd;
    ssize_t n;
    char buff[MAXLINE];
 
    if((n=Read(readfd,buff,MAXLINE))==0)
        err_quit("end-of-file while reading pathname");
    buff[n]='';
 
    if((fd=open(buff,O_RDONLY))<0){
        snprintf(buff+n,sizeof(buff)-n,":can't open, %s
",
                strerror(errno));
        n=strlen(buff);
        Write(writefd,buff,n);
    }else{
        while((n=Read(fd,buff,MAXLINE))>0)
            Write(writefd,buff,n);
        Close(fd);
    }
}

popen/pclose

popen的打开属性为读或写
写时表示向子进程传递命令, 读时表示从子进程读取命令的执行结果

//头文件和其它包裹函数同pipe
void Fputs(const char *ptr,FILE *fp){
    if(fputs(ptr,fp)==EOF)
        err_quit("fputs errro");
}
FILE *Popen(const char *command,const char *type){
    FILE *fp;
    if((fp=popen(command,type)) == NULL)
        err_quit("popen error");
    return fp;
}
void Pclose(FILE *fp){
    if(pclose(fp) == -1)
        err_quit("pclose error");
} 
 
int main(int argc, char *argv[]){
    size_t n;
    char buff[MAXLINE],command[MAXLINE];
    FILE *fp;
 
    Fgets(buff,MAXLINE,stdin);
    n=strlen(buff);
    if(buff[n-1]=='
')
        n--;
 
    snprintf(command,sizeof(command),"cat %s",buff);
    fp=Popen(command,"r");
 
    while(Fgets(buff,MAXLINE,fp) != NULL)
        Fputs(buff,stdout);
 
    Pclose(fp);
    exit(0);
}

FIFO

在管道的基础上, 增加了管道命名, 在物理磁盘上会多出一个管道文件, 可用于非亲代进程之间传递消息
mkfifo函数用于创建命名管道, 默认含有O_CREAT | O_EXCL属性, 要么创建新管道文件, 要么出错返回EEXIST
管道文件打开模式要么只读要么只写, 不支持lseek

//头文件和其它包裹函数同pipe
#include <sys/types.h>
#include <sys/stat.h>

int Open(const char *pathname,int flag,mode_t mode){
    int fd;
    if((fd=open(pathname,flag,mode)) == -1)
        err_quit("open error");
    return fd;
}
void Unlink(const char *pathname){
    if(unlink(pathname) == -1)
        err_quit("unlink error");
}

#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define FIFO1 "./fifo.1"
#define FIFO2 "./fifo.2"
int main(int argc, char *argv[]){
   int readfd,writefd;
   pid_t childpid;
 
   if((mkfifo(FIFO1,FILE_MODE)) && (errno != EEXIST))
       err_quit("can't create %s",FIFO1);
   if((mkfifo(FIFO2,FILE_MODE)<0) && (errno != EEXIST)){
       Unlink(FIFO1);
       err_quit("can't create %s",FIFO2);
   }
 
   if((childpid=fork())<0)
       err_quit("fork error");
   else if(childpid==0){
       readfd=Open(FIFO1,O_RDONLY,0);
       writefd=Open(FIFO2,O_WRONLY,0);
 
       server(readfd,writefd);
       exit(0);
   }
 
   writefd=Open(FIFO1,O_WRONLY,0);
   readfd=Open(FIFO2,O_RDONLY,0);
 
   client(readfd,writefd);
 
   Waitpid(childpid,NULL,0);
 
   Close(readfd);
   Close(writefd);
 
   Unlink(FIFO1);
   Unlink(FIFO2);
   exit(0);
}
原文地址:https://www.cnblogs.com/cfans1993/p/5730266.html