如何创建管道——pipe
我们有一个这样的场景:主程序希望与子程序进行通信。我们用pipe()函数为他们创建管道,这样他们就可以通过管道来通信了。
为了演示方便我们只考虑:
子程序把数据发送到父进程中来的情况。因此要用管道把子进程的标准输出和父进程的标准输入连接起来
我们将用pipe()函数建立管道。每当我们打开数据流时,它都会加入描述符表。pipe()函数也是如此,它创建两条相连的数据流,并把它们加到描述符表中,然后只要我们往其中一条数据流中写数据,就可以从另一条数据流中读取。pipe()在描述符表中创建这两项时,会把它们的文件描述符存放在一个包含两个元素的数组中。
int fd[2]; //文件描述符将保存在fd数组中。
if(pipe(fd) == -1){ fprintf(stderr,"Can't create the pipe!"); exit(2);
}
- 1
- 2
- 3
- 4
- 5
pipe()函数创建了管道,并返回了两个描述符:fd[0]用来从管道读数据,fd[1]用来向管道写数据。我们将在父、子进程中使用这两个描述符。
我们通过一个实例来说明:
aaa.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void open_url(char *url);
int main(){ int fd[2]; if(pipe(fd) == -1){ //创建管道,并把文件描述符保存在fd[0]和fd[1]中。 fprintf(stderr,"%s\n","Can't create the pipe!"); exit(1); } pid_t pid = fork(); if(pid == -1){ fprintf(stderr,"%s\n","Can't fork process!"); exit(2); } if(!pid){ //能进这里,表示已在子进程中 dup2(fd[1],1); //把标准输出设为管道写入端 close(fd[0]); //因为子进程不会去读取管道,因此将读取端关闭 if(execl("bbb","bbb",NULL) == -1){ fprintf(stderr,"%s\n","Can't open subprocess"); exit(1); } } //从这开始是属于父进程的 dup2(fd[0],0); //把标准输入设为管道读取端 close(fd[1]);//因为父进程不会向子进程发数据,无需写入管道,因此将写入端关闭 char line[255]; while(fgets(line,255,stdin)){ open_url(line+1); } return 0;
}
void open_url(char *url){ char launch[255]; //sprintf(launch,"cmd /c start %s",url); //在windows上打开网页 // system(launch); sprintf(launch,"x-www-browser '%s' &",url);//在Linux上打开网页 system(launch); //sprintf(launch,"open '%s'",url); //在Mac上打开网页 //system(launch);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
bbb.c
#include <stdio.h>
int main(){ char line[255]; fgets(line,255,stdin); printf("%s",line); return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
编译运行:
~/Desktop/MyC$ gcc aaa.c -o aaa
~/Desktop/MyC$ gcc bbb.c -o bbb
~/Desktop/MyC$ ./aaa
|
- 1
- 2
- 3
- 4
查进程信息:
~$ ps -ef
UID PID PPID C STIME TTY TIME CMD
wong 17525 5363 0 17:47 pts/1 00:00:00 ./aaa
wong 17526 17525 0 17:47 pts/1 00:00:00 bbb
- 1
- 2
- 3
- 4
输入地址按回车:
~/Desktop/MyC$ ./aaa
http://www.baidu.com
- 1
- 2
接着就会打开浏览器。
管道是文件吗?这不一定。这取决于操作系统创建管道的方式,一般来说用pipe()创建的管道都不是文件。而创建基于文件的管道,通常叫做有名管道或FIFO文件(先进先出文件)。
因为基于文件的管道有名字,所以两个进程只要知道管道的名字也能用它来通信,即使它们是非父子进程关系。要使用有名管道,可以通过使用mkfifo()系统调用来实现。如果不是通过文件来实现管道的话,那通常是用内存,数据写到内存某个位置,然后再从另一个位置读取。
如果试图读取一个空的管道,也不会发生错误,因为程序会等待管道中出现东西。
父进程是如何知道子进程结束的?
其实,当子进程结束时,管道会关闭。fgets()将会收到EOF(End Of File,文件结束符) ,于是fgets()函数返回0,循环就结束了。
另外,管道只能单向通信。但是可以通过创建两个管道,一个从父进程连接到子进程,另一个从子进程连接到父进程来实现双向通信 。
谢谢阅读!
文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/weixin_40763897/article/details/87627832
- 点赞
- 收藏
- 关注作者
评论(0)