管道和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('\n' == 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\n",FIFO1);}
         
         if((mkfifo(FIFO2, FILE_MODE) < 0) && (errno != EEXIST))
         {        
                   unlink(FIFO1);
                   printf("can'tcreate %s\n", 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才从文件系统删除

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值