• 管道和FIFO


    管道和FIFO

    1.1    管道和FIFO简介

             管道是最初的unixIPC形式,广义的管道包含无名管道(狭义的管道)和有名管道(FIFO)

             无名管道采用pipe函数创建,只能由亲缘关系的进程使用;有名管道突破了亲缘关系的限制,可以在不同进程间实现数据共享,管道和FIFO都是使用通常的read和write函数访问的,其由mkfifo函数创建,然后用open函数打开使用。

             对管道或FIFO的write总是往末尾添加数据,对它们的read则总是从开头返回数据。这相当于队列。如果对其调用lseek,那就返回ESPIPE错误。

             另外标准I/O库提供了popen函数和pclose函数,用于创建一个管道并启动另外一个进程,该进程要么从该管道读出标准输入,要么往该管道写入标准输出。

    #include <stdio.h>

    FILE *popen(const char *command, const char*type);

    int pclose(FILE *stream);

    p. s: shell脚本中管道符“|”的实现估计就是利用这个

    1.1.1  原理

    管道的原理图如下所示:

     

             从原理图中可以看出,父进程和子进程通过管道进行通信,当读写数据时要进行用户态和内核态的穿越(使用read和write进行读写)

    1.1.2  程序示例:

    1)      pipe

             下面的程序演示了父子进程间通过pipe进行通信,当输入hello时,子进程传递给父进程,再由父进程返回给子进程输出到标准输出。

    server.c
    
    #include <unistd.h>
    #include <stdio.h>
    #define MAXLINE 100
    void server(int readfd, int writefd)
    {
             intfd;
             ssize_tn;
             charbuff[MAXLINE + 1 ];
                      
             if( (n = read(readfd, buff, MAXLINE)) == 0)
             {
                       fprintf(stderr,"end-of-file while reading pathname");
             }
             buff[n]= 0;
             //printf("readfrom client, buff = %s, n = %d", buff, n);
             write(writefd,buff, n);
    }
     
    client.c
    #include <unistd.h>
    #include <stdio.h>
    #define MAXLINE 100
    void client(int readfd, int writefd)
    {
             size_tlen;
             intn;
             charbuff[MAXLINE];
            
             fgets(buff,MAXLINE, stdin);
             len= strlen(buff);
             if('
    ' == buff[len - 1])
                       len--;
             //writepathname to IPC channel
             write(writefd,buff, len);
            
             //readfrom IPC, write to standard output
             while((n= read(readfd, buff, MAXLINE)) > 0)
                       write(STDOUT_FILENO,buff, n);
    }
    mainpipe.c
    #include "unistd.h"
    #include "stdio.h"
    void client(int, int);
    void server(int, int);
    int main(int argc, char **argv)
    {
             intpipe1[2];
             intpipe2[2];
             pid_tchildpid;
            
             //createtwo pipes
             pipe(pipe1);
             pipe(pipe2);
     
             if(0 == (childpid = fork())) //child process
             {
                       close(pipe1[1]);//close the writePort
                       close(pipe2[0]);//close the readPort
     
                       server(pipe1[0],pipe2[1]);
                       exit(0);
             }
     
             //parentprocess
             close(pipe1[0]);//close the readPort
             close(pipe2[1]);//close the writePort
     
             client(pipe2[0],pipe1[1]);
            
             waitpid(childpid,NULL, 0);
             exit(0);
    }
    

    makefile

    OBJS=mainpipe.o client.o server.o

    mainpipe:${OBJS}

             g++-o $@ mainpipe.o client.o server.o

    clean:

             rm-f mainpipe ${OBJS}

    2)      FiFO

             下面的程序演示了使用FIFO进行两个无亲缘关系进程间通信(其中server.c和client.c同上):

    server_main.c
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include "fifo.h"
    #include <stdio.h>
    #include <fcntl.h>
    #include <errno.h>
     
    void server(int, int);
    int main(int argc, char **argv)
    {
             intreadfd, writefd;
             if((mkfifo(FIFO1, FILE_MODE) < 0) && (errno != EEXIST))
             {        printf("can't create %s
    ",FIFO1);}
             
             if((mkfifo(FIFO2, FILE_MODE) < 0) && (errno != EEXIST))
             {        
                       unlink(FIFO1);
                       printf("can'tcreate %s
    ", FIFO2);
             }
             
             readfd= open(FIFO1, O_RDONLY, 0);
             writefd= open(FIFO2, O_WRONLY, 0);
     
             server(readfd,writefd);
             exit(0);
             
    }
     client_main.c
    #include "fifo.h"
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int main(int argc, char **argv)
    {
             intreadfd, writefd;
             writefd= open(FIFO1, O_WRONLY, 0);
             readfd= open(FIFO2, O_RDONLY, 0);
             
             client(readfd,writefd);
             
             close(readfd);
             close(writefd);
             
             exit(0);
    }

    makefile

    OBJS=server_main.o client_main.o client.oserver.o

    all: server_main client_main

    client_main:${OBJS}

             g++-o $@ client_main.o client.o server.o

    server_main:${OBJS}

             g++-o $@ server_main.o client.o server.o

    clean:

             rm-f server_main client_main ${OBJS}

     

    1.1.3  总结

             最后对两者的不同点做一个比较:

    1、   适用范围:FIFO即可以用于亲缘关系的进程通信,又可用于无亲缘关系的进程通信

    2、   创建函数:创建并打开一个管道只需要调用pipe,创建并打开一个FIFO则需在调用mkfifo之后再调用open

    3、   打开管道后的删除方式:管道在所有进程最终都关闭它之后自动消失。FIFO的名字则只有通过调用unlink才从文件系统删除

  • 相关阅读:
    17 正在表达式
    16 css实现模糊背景
    15 VScode 使用相关
    14 CSS题目附答案
    13 form表单
    12 postgresql数据库备份和恢复
    11 vs2015 连接oracle 11g 数据库及相关问题
    10 windows server 2012R2 发布MVC框架网站注意事项
    9 ArcGIS Server 性能优化
    Project Euler P4 Largest palindrome product 题解
  • 原文地址:https://www.cnblogs.com/OpenLinux/p/5020699.html
Copyright © 2020-2023  润新知