Head First C 第十章 进程间通信 创建管道

原创
2016/04/10 21:58
阅读数 94

Head First C 第十章 进程间通信 创建管道

我们已经可以通过重定向的方式,将子进程的输出重定向到文件,但我们想从进程中直接读取数据,如何使实现。

用管道连接进程

我们曾经用一个命令来连接进程,那就是管道:

  • python fake_rss.py | grep 'naruto'

可以用管道把一个进程的输出连接到另一个进程的输入。 管道两侧的命令是父子关系。

  1. 命令行创建了父进程。
  2. 父进程在子进程中克隆出了fake_rss.py脚本。
  3. 父进程用管道把子进程的输出连接到自己的输入。
  4. 父进程运行grep命令。

如果想在c代码中,而不是命令行中实现管道连接,该怎么做呢。

在浏览器中打开链接

我们要做以下两件事:

  1. 从python脚本的输出中获取链接
  2. 在浏览器中打开链接
如何创建管道

我们要在进程中创建两条新的流,用于管道的读取与写入。

数据流
0 stdin
1 stdout
2 stderr
3 管道读取端
4 管道写入端
  1. pipe()函数建立管道 因为子进程要把数据发送到父进程里,所以要用管道连接子进程的标准输入父进程的标准输出。 我们说过,每当打开数据流时,它都会加入描述符表。pipe()函数也是如此,它创建两条相连的数据流,并把它们加入描述符表中。 这样你只要从一条数据流中写入数据,就能从另一条数据流中读取
  2. 描述符存放在一个包含两个元素的数组中
    
    	int fd[2];
    	if (pipe(fd) == -1) {
    	    error("Can't create pipe");
    	}
    
  3. fd[1]写管道,fd[0]读管道 1. 在子进程中: - 需要关闭管道的fd[0]端 - 修改子进程的标准输出,让它指向fd[1]对应的数据流 因为子进程不会从管道中读取数据,子进程发送给标准输出的数据都会写入到管道中。 2. 在父进程中: - 需要关闭管道的fd[1]端,因为父进程不需要往管道中写入数据 - 修改父进程的标准输入,使其从描述符fd[0]的数据流中读取数据。
使用管道进行进程间通信
  1. 对于子进程的操作
    if (pid == 0) {
    
        dup2(fd[1], 1);
        close(fd[0]);
        execlp("python", "python", "./fake_rss.py", NULL);
    

} 2. 父进程的操作c dup2(fd[0], 0); close(fd[1]); char line[255]; while (fgets(line, sizeof(line) / sizeof(char), stdin)) { if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = 0; printf("Got url :%s\n", line);

pid_t pid2 = fork();
if (pid2 == 0) {
  open_url(line);
}

} ``` 父进程要做的是: 1. 将标准输入stdin重定向到*fd[0]*的数据流。 2. 用一个while循环从stdin读入数据,判断条件为读入的结果(当执行脚本结束时会返回EOF,fgets()返回0,循环结束)。 3. 再fork()一次,用于创建多个子进程打开多个url。

有名管道

有名管道是基于文件的管道,也叫做FIFO(First In First Out)文件。 因为基于文件的管道有名字,所以两个进程只要知道管道的名字就能用它来通信,即使它们不是父子进程。 使用系统调用mkfifo()可以创建有名管道。

代码

process communication with pipe

展开阅读全文
打赏
1
6 收藏
分享
加载中
更多评论
打赏
0 评论
6 收藏
1
分享
返回顶部
顶部