• 管道和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);
    }
    
  • 相关阅读:
    哈夫曼树与哈夫曼编码
    HTML & CSS整理
    MYSQL整理
    数据库报告存档
    一些网络报错信息记录
    复活~
    你必须知道的Docker数据卷(Volume)
    Sql Prompt 10下载安装破解图文教程
    通过Logstash由SQLServer向Elasticsearch同步数据
    Linux(CentOS)配置Docker随宿主机自启,容器自启( --restart=always)
  • 原文地址:https://www.cnblogs.com/cfans1993/p/5730266.html
Copyright © 2020-2023  润新知