1.概述
管道通信是多个进程之间进行的通信方式之一。无名管道用于父进程与子进程之间进行通信的场合,命名管道用于任何两个进程之间的通信场合。管道仅仅是将某个进程的输出和另一个进程的输入相连接的单向通信的办法。
2.无名管道
无名管道采用pipe()函数来创建,其函数原型为:
#include<unistsd.h>
intpipe(int filedes[2]);
其中的数组filedes是一个文件描述符数组,用于保存管道返回的两个文件描述符。数组中的第一个函数是为读操作而创建和打开的,而第二个函数是为写操作而创建和打开的。直观地说,filedes[1]的输出变成了filedes[0]的输入。示例代码如下:
/*-------------------无名管道操作-------------------------------*/
#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
intmain()
{
intpipe_fd[2];
pid_tpid;
charbuf_r[100];
char*p_wbuf;
intr_num;
memset(buf_r,0, sizeof(buf_r));
if(pipe(pipe_fd)< 0)
{
printf("pipecreate error!\n");
return-1;
}
if((pid= fork()) == 0)
{
printf("\n");
close(pipe_fd[1]);//关闭读操作
sleep(2);
if((r_num= read(pipe_fd[0], buf_r, 100)) > 0)
{
printf("%dnumbers read from the pipe is %s\n", r_num, buf_r);
}
close(pipe_fd[0]);
exit(0);
}
elseif(pid > 0)
{
close(pipe_fd[0]);//关闭写操作
if(write(pipe_fd[1],"Hello", 5) != -1)
printf("parentwrite surcess\n");
if(write(pipe_fd[1],"pipe", 5) != -1)
printf("parentwrite success\n");
close(pipe_fd[1]);
sleep(2);
waitpid(pid,NULL, 0);
exit(0);
}
}
3.命名管道
命名管道的工作方式与普通的管道非常相似,但也有一些区别。
-
在文件系统中,命名管道是以设备特殊文件的形式存在的。
-
不同的进程可以通过命名管道共享数据。
可以利用makefifo函数来创建命名管道,其他的操作过程与文件操作类似。相关例子代码如下所示:
/*------------命名管道的读过程-------------*/
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#defineFIFO "/tmp/myfifo"
int
main(intargc, char **argv)
{
charbuf_r[100];
intfd;
intnread;
if((mkfifo(FIFO,O_CREAT | O_EXCL) < 0) && (errno != EEXIST))
printf("cannotcreate fifoserver\n");
printf("Preparingfor reading bytes..\n");
memset(buf_r,0 , sizeof(buf_r));
fd= open(FIFO, O_RDONLY | O_NONBLOCK, 0);
if(fd== -1)
{
perror("openFIFO failed!\n");
exit(1);
}
while(1)
{
memset(buf_r,0, sizeof(buf_r));
if((nread= read(fd, buf_r, 100)) == -1)
{
if(errno== EAGAIN)
printf("nodata yet]n");
}
printf("read%s, from FIFO\n", buf_r);
sleep(1);
}
pause();
unlink(FIFO); //删除命名管道
}
/*-------------命名管道写进程---------------*/
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#defineFIFO_SERVER "/tmp/myfifo"
int
main(intargc, char ** argv)
{
intfd;
charw_buf[100];
intnwrite;
fd= open(FIFO_SERVER, O_WRONLY | O_NONBLOCK, 0);
if(fd== -1)
{
if(errno== ENXIO)
printf("openerror, no reading process\n");
}
if(argc== 1)
printf("Pleasesend something\n");
strcpy(w_buf,argv[1]);
if((nwrite= write(fd, w_buf, 100)) == -1)
{
if(errno== EAGAIN)
printf("nodata yet\n");
}
else
printf("write%d characters: %s\n", nwrite, w_buf);
}
4.流管道
popen()通过创建一个管道,调用fork函数,然后启动shell来打开一个进程。
popen()函数的原型如下:
#include<stdio.h>
FILE*popen(const char *command, const char *type);
intpclose(FILE *stream);
相关的如下所示:
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#defineBUFSIZE 1024
intmain()
{
FILE*fp;
char*cmd = "ps -ef";
charbuf[BUFSIZE];
buf[BUFSIZE]= '\0';
if((fp=popen(cmd, "r")) ==NULL)
perror("popen");
while((fgets(buf,BUFSIZE, fp)) != NULL)
printf("%s",buf);
pclose(fp);
exit(0);
}