C 语言 管道连接进程实现进程通信
书上的例子是实时读取生成的数据,还是上面的例子,rssgroup.py 脚本加上 -u,可以显示找到的 url,如:
export RSS_FEED=http://rss.news.sohu.com/rss/guoji.xml python rssgossip.py -u sohu www.sohu.com http://www.sohu.com
学习了管道符,但是没有讲管道具体的原理是什么,很幸运,这一节涉及到了。
2.1 管道两侧的命令是父子关系
如上的命令,可以解析如下图:
在 C 中有 pipe()
设置管道
2.2 pipe() 函数建立管道
用 pipe()
连接子进程的标准输出和父进程的标准输入。pipe() 建立两条数据流(fd[0]、fd[1])写入表中, 通过返回的文件描述符就可以在两端操作了,pipe() 在描述符中创建这两项时,会把它们的文件描述符保存在一个包含两个元素的数组中:
pipe() 函数创建了管道,并返回了两个描述符:
- fd[1] 用来向管道写数据
- fd[0] 用来从管道读数据
你将在 父、子进程中使用这两个描述符。
2.2.1 子进程
在这个项目中,子进程只需要写就 ok 了, 所以可以关闭管道的 f[0] 端,然后修改其标准输出指向 f[1] 数据流。
2.2.2 父进程
父进程只需要读就行了,所以需要关闭 f[1]端,然后重定向父进程的标准输入,让它从描述符 fd[0] 对应的数据流中读取数据:
2.2.3 实例:浏览器打开网页
我们尝试上面程序读取到的网址,调用系统函数打开浏览器浏览网页。
#include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> //定义一个通用的错误处理方法 void error(char *msg){ fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(1); // exit(1) 会立刻终止程序并把`退出状态`设为 1 } // 打开浏览器 void open_url(char *url) { char launch[255]; // sprintf(launch, "cmd /c start %s", url); // system(launch); // windows // sprintf(launch, "x-www-browser '%s' &", url); // system(launch); // linux sprintf(launch, "open '%s'", url); system(launch); // mac } int main(int argc, char *argv[]) { char *phrase = argv[1]; char *vars[] = {"RSS_FEED=http://rss.news.sohu.com/rss/guoji.xml", NULL}; int fd[2]; //这个数组保存管道的描述符 //创建管道 if (pipe(fd) == -1) { error("创建管道失败"); } //fork 进程 pid_t pid = fork(); //判断 fork 是否成功 if (pid == -1) { error("fork 进程失败"); } //这段代码会修改子进程,因为 pid 为 0 if (!pid) { close(fd[0]); // 0:read dup2(fd[1], 1); // 标准写入重定向到 fd[1],设为管道输入端 //执行系统调用 int pid = execle("/usr/bin/python", "/usr/bin/python", "./rssgossip.py","-u", phrase, NULL, vars); if (pid == -1) { error("系统调用失败"); } } //父进程 dup2(fd[0], 0); //标准读取重定向到 fd[0],设为管道输出端 close(fd[1]); //1:write char line[255]; while (fgets(line, 255, stdin)) { //将从标准输入读取数据,因为管道连入了标准输入,也可以是 fd[0] // 如果 line 以 tab 开头则是 url, line+1 是 tab 以后的字符串 if (line[0] == '\t') { printf("%s\n", line+1); open_url(line + 1); } } return 0; }
运行后就能发现自动打开对应的网页了。
2.3 小结
- 父子进程可以用管道通信
- pipe() 函数创建一个管道和两个描述符
- 一个描述符是管道的读取端,另一个是写入端
- 可以把标准输入和标准输出重定向到管道
- 父子进程各自使用管道的一端
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: C 语言 信号量
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论