zoukankan      html  css  js  c++  java
  • 管道和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才从文件系统删除

  • 相关阅读:
    POJ 1251 Jungle Roads
    1111 Online Map (30 分)
    1122 Hamiltonian Cycle (25 分)
    POJ 2560 Freckles
    1087 All Roads Lead to Rome (30 分)
    1072 Gas Station (30 分)
    1018 Public Bike Management (30 分)
    1030 Travel Plan (30 分)
    22. bootstrap组件#巨幕和旋转图标
    3. Spring配置文件
  • 原文地址:https://www.cnblogs.com/OpenLinux/p/5020699.html
Copyright © 2011-2022 走看看