C 语言 数据流和重定向

发布于 2024-05-13 08:43:47 字数 3695 浏览 20 评论 0

1.1 数据流

数据流:就是流动的数据,数据从一个进程流出,流入另一个进程,除了标准输出,标准输入,标准错误外还有其他形式的数据流,如文件连接,网络连接。

进程含有:

  • 正在运行的程序
  • 堆和栈数据空间
  • 记录数据流的方向

1.2 文件描述符

进程用文件描述符表示数据流, 是一个数字,代表一条数据流。把文件描述符和对应的数据流保存到描述符表中。这张表长这个样:

前三项一直不变:

  • 0 : 标准输入
  • 1 : 标准输出
  • 2 : 标准错误

其他项要么空,要么是进程打开的数据流。

1.3 重定向

重定向:替换数据流, 标准输入/输出/错误在描述符表中的位置是固定的,但它们指向的数据流可以改变。也就是说,如果想重定向标准输出,只需要修改表 中 1 号描述符对应的数据流就行了。

所有向标准输出发送数据的函数会先查看描述符表,看 1 号描述符指向哪条数据流,然后再把数据写到这条数据流中,printf() 便是如此。

1.4 对文件描述符的操作

有如下相关函数:

  • fileno() : 返回描述符号
  • dup2() : 复制数据流

1.4.1 fileno()

1.4.2 dup2()

1.4.3 实例:rss 源检索输出到文件中

还是上一章节的例子,只有一个 rss 源:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>

//定义一个通用的错误处理方法
void error(char *msg){
  fprintf(stderr, "%s: %s\n", msg, strerror(errno));
  exit(1);    // exit(1) 会立刻终止程序并把`退出状态`设为 1
}

int main(int argc, char *argv[]) {
  char *phrase = argv[1];
  char *vars[] = {"RSS_FEED=http://rss.news.sohu.com/rss/guoji.xml", NULL};
  //打开文件
  FILE *f = fopen("output.txt", "w");
  //判断打开文件是否成功
  //如果不能以写的方式打开,则`f=0`
  if (!f) {
    error("文件 output.txt 打开失败");
  }
  
  //fork 进程
  pid_t cf = fork();
  //判断 fork 是否成功
  if (cf == -1) {
    error("fork 进程失败");
  }
  
  //这段代码会修改子进程,因为 pid 为 0
  if (!cf) {
    //重定向,让 1 号描述符指向 output.txt 文件
    if (dup2(fileno(f), 1) == -1) {
      error("重定向失败");
    }
    //执行系统调用
    int pid = execle("/usr/bin/python", "/usr/bin/python", "./rssgossip.py", phrase, NULL, vars);
    if (pid == -1) {
      error("系统调用失败");
    }
  }
  return 0;
}

我们运行下代码:

./rss sohu 
cat output.txt

如果幸运的话,里面会看到内容,这里我故意放慢 rssgossip.py 运行, 加上了 time.sleep(3),让它 3s 后才开始处理。你会看到 output.txt 文件里面为空,等到 3s 过去后才会有值。

➜  intoC git:(master) ✗ ./rss sohu  
➜  intoC git:(master) ✗ cat output.txt
➜  intoC git:(master) ✗ cat output.txt
➜  intoC git:(master) ✗ cat output.txt
➜  intoC git:(master) ✗ cat output.txt
www.sohu.com 

也就是说 rss 程序启动独立进程运行 rssgossip.py,而子进程一创建就会父进程没关系了,rssgossip.py 还没有完成任务,rss 就结束了,所以 output.txt 为空,也 就是说,操作系统必须提供一种方式,让你等待子进程完成任务。

1.5 waitpid() 函数

针对上面的问题, waitpid() 函数会让子进程运行结束后才返回。我们在程序的最后面加上下面的代码:

int pid_status;
if (waitpid(cf, &pid_status, 0) == -1) {
  error("等待子进程时发生错误");
}
return 0;

然后在运行程序:

➜  intoC git:(master) ✗ gcc rss.c -o rss
➜  intoC git:(master) ✗ ./rss sohu     
➜  intoC git:(master) ✗ cat output.txt 
www.sohu.com 

rss 程序不是立即就退出的,而是等一会,等待 rssgossip.py 完成后再退出。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

关于作者

失与倦"

暂无简介

0 文章
0 评论
24 人气
更多

推荐作者

qq_E2Iff7

文章 0 评论 0

Archangel

文章 0 评论 0

freedog

文章 0 评论 0

Hunk

文章 0 评论 0

18819270189

文章 0 评论 0

wenkai

文章 0 评论 0

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