【问题标题】:Non-blocking pipe using popen?使用popen的非阻塞管道?
【发布时间】:2010-12-16 16:28:11
【问题描述】:

我想使用popen() 打开一个管道并对其进行非阻塞“读取”访问。

我怎样才能做到这一点?

(我发现的例子都是阻塞/同步的)

【问题讨论】:

    标签: c linux pipe popen


    【解决方案1】:

    这样设置:

    FILE *f = popen("./output", "r");
    int d = fileno(f);
    fcntl(d, F_SETFL, O_NONBLOCK);
    

    现在你可以阅读:

    ssize_t r = read(d, buf, count);
    if (r == -1 && errno == EAGAIN)
        no data yet
    else if (r > 0)
        received data
    else
        pipe closed
    

    完成后,清理:

    pclose(f);
    

    【讨论】:

    • 管道,作为一个文件指针,本质上是缓冲的,有没有保证通过直接使用文件描述符你不会错过被拉入文件缓冲区的东西,或者这可以只要不先调用 fget/fread/etc 就可以保证?
    【解决方案2】:

    popen() 内部调用 pipe()fork()dup2()(将子进程的 fds 0/1/2 指向管道)和 execve()。您是否考虑过使用这些来代替?在这种情况下,您可以使用fcntl() 将您读取的管道设置为非阻塞。

    更新:这是一个示例,仅用于说明目的:

    int read_pipe_for_command(const char **argv)
    {
       int p[2];
    
       /* Create the pipe. */
       if (pipe(p))
       {
          return -1;
       }
    
       /* Set non-blocking on the readable end. */
       if (fcntl(p[0], F_SETFL, O_NONBLOCK))
       {
          close(p[0]);
          close(p[1]);
          return -1;
       }
    
       /* Create child process. */
       switch (fork())
       {
          case -1:
              close(p[0]);
              close(p[1]);
              return -1;
          case 0:
              /* We're the child process, close read end of pipe */
              close(p[0]);
              /* Make stdout into writable end */
              dup2(p[1], 1);
              /* Run program */
              execvp(*argv, argv);
              /* If we got this far there was an error... */
              perror(*argv);
              exit(-1);
          default:
              /* We're the parent process, close write end of pipe */
              close(p[1]);
              return p[0];
       }
    }
    

    【讨论】:

    • 不应该是:if (pipe(p)
    • @Aktau 我更喜欢我的版本。系统调用将在成功时返回 0。 if 语句测试非零。
    • 你说得对,你的版本也完全正确,我在想其他系统调用!
    • 注意父子 case 是交换的:kill() 返回 0 给子,而不是父。
    • 谢谢卢卡,你是对的。我批准了编辑。 (就在我回答之后的 9 年!)
    【解决方案3】:

    从未尝试过,但我不明白为什么您无法使用 fileno() 获取文件描述符,使用 fcntl() 设置为非阻塞,并使用 read()/write()。值得一试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 1970-01-01
      • 2016-08-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多