C 语言 管道连接进程实现进程通信

发布于 2024-04-23 08:56:09 字数 3525 浏览 18 评论 0

书上的例子是实时读取生成的数据,还是上面的例子,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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

花间憩

暂无简介

0 文章
0 评论
24 人气
更多

推荐作者

内心激荡

文章 0 评论 0

JSmiles

文章 0 评论 0

左秋

文章 0 评论 0

迪街小绵羊

文章 0 评论 0

瞳孔里扚悲伤

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文