zoukankan      html  css  js  c++  java
  • 进程间通信(二)


    传递更多的数据

    到目前为止我们所用的机制只是简单的在一个fread或是fwrite中发送或是接收全部的数据。有时我们也许以更小的尺寸发送数据,或是也许我们并不知道输出的大小。为了避免声明一个大的缓冲区,我们可以使用多个fread或是fwrite调用并分别处理这些数据。

    下面是一个程序,popen3.c,由一个管道中读取所有的数据。

    试验--由一个管道读取大量的数据

    在这个程序中,我们由一个被调用的ps -alx进程读取数据。并没有办法预先知道会有多少输出,所以我们必须由管道中多次读取。

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

    int main()
    {
        FILE *read_fp;
        char buffer[BUFSIZ +1];
        int chars_read;

        memset(buffer,'/0',sizeof(buffer));
        read_fp = popen("ps -ax","r");
        if(read_fp != NULL)
        {
            chars_read = fread(buffer,sizeof(char),BUFSIZ,read_fp);
            while(chars_read > 0)
            {
                buffer[chars_read - 1] = '/0';
                printf("Reading:-/n %s/n",buffer);
                chars_read = fread(buffer,sizeof(char),BUFSIZ,read_fp);
            }
            pclose(read_fp);
            exit(EXIT_SUCCESS);
        }
        exit(EXIT_FAILURE);
    }

    我们得到的输出结果如下:

    $ ./popen3
    Reading:-
        PID TTY STAT  TIME COMMAND
         1 ? S       0:04 init
         2 ? SW      0:00 [kflushd]
         3 ? SW      0:00 [kpiod]
         4 ? SW      0:00 [kswapd]
         5 ? SW<     0:00 [mdrecoveryd]
    ...
      240 tty2 S     0:02 emacs draft1.txt
    Reading:-
      368 tty1 S     0:00 ./popen3
      369 tty1 R     0:00 ps -ax
    ...

    工作原理

    这个程序以与popen1.c相类似的方法使用"r"参数调用popen。但是这一次,程序会继续由文件流中读取数据,直到没有更多的数据。注意,尽管ps命令的执行需要一些时间,Linux会安排进程调度,从而在可能时两个程序同时运行。如果读进程,popen3,没有输入数据,他会挂起,直到有输入数据。如果写进程,ps,产生了更多的可缓冲的数据,他就会挂起,直到读进程消化掉其中的一些数据。

    popen是如何实现的

    popen调用通过首先调用shell,sh,将command字符串作为参数传递给他来运行我们所请求的程序。这有两个效果,一个是好的,而另一个并不是这样好。

    在Linux(同时在所有的类Unix系统)中,所有的参数扩展都是通过shell来完成的,所以在程序被调用之前调用shell来分析命令字符串会允许在程序启动之前完成任意的shell扩展,例如,确定'*.c'实际指向哪些文件。这通常是非常有用的,而且这允许使用popen来启动复杂的shell命令。其他的进程创建函数,例如execl,其调用可以更为复杂,因调用进程必须执行其自己的shell扩展。

    使用shell的另一个效果就是对于每一个popen调用,必须为所请求的程序调用一个shell。从而每一个popen调用就会另外两个额外进程,这就会使得popen函数就系统资源而言更为昂贵,而且目标命令的调用速度更慢。

    下面是程序popen4.c,我们可以模拟popen的行为。我们通过cat文件来计算所有popen例子源程序的行数,然后通过管道输出给wc -l,后者会计算这些行数。在命令行,等同的命令如下:

    $ cat popen*.c | wc -l

    实际上,wc -l poen*.c命令输入更为简单而且更为高效,但是这个例子是为了演示这些原则。

    试验--popen启动一个Shell

    这个程序实际上使用前面的命令,但是通过popen可以读取结果:

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

    int main()
    {
        FILE *read_fp;
        char buffer[BUFSIZ +1];
        int chars_read;

        memset(buffer,'/0',sizeof(buffer));
        read_fp = popen("cat popen*.c | wc -l","r");
        if(read_fp != NULL)
        {
            chars_read = fread(buffer,sizeof(char),BUFSIZ,read_fp);
            while(chars_read > 0)
            {
                buffer[chars_read -1] = '/0';
                printf("Reading:-/n %s/n",buffer);
                chars_read = fread(buffer,sizeof(char),BUFSIZ,read_fp);
            }
            pclose(read_fp);
            exit(EXIT_SUCCESS);
        }
        exit(EXIT_FAILURE);
    }

    当我们运行这个程序,我们会得到下面的输出:

    Reading:-
     98

    工作原理

    这个程序证明了被调用的shell将popen*.c扩展为所有以popen开头并以.c结束的文件列表,同时处理管道符号,并将cat的输入传递给wc。我们在一个popen调用中调用shell,cat程序以及wc程序,并将结果重定向。调用命令的程序只看到最终的结果。

  • 相关阅读:
    大工程(bzoj 3611)
    消耗战(bzoj 2286)
    Computer(hdu 2196)
    文件排版(codevs 1300)
    洛谷 P2015 二叉苹果树
    洛谷 P2014 选课
    洛谷 P1352 没有上司的舞会
    COGS 505. 城市
    洛谷 P1306 斐波那契公约数
    洛谷 P1962 斐波那契数列
  • 原文地址:https://www.cnblogs.com/dyllove98/p/2461944.html
Copyright © 2011-2022 走看看