2009-11-14 5 views

ответ

25

Setup так:

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); 
+0

Прекрасно работает ... спасибо! – jldupont

+0

Труба, являющаяся указателем FILE, по сути буферизуется, есть ли уверенность в том, что, используя дескриптор файла напрямую, вы не пропустите что-то, что было вложено в буфер файлов, или это можно гарантировать, пока вы не 'сначала вызвать fget/fread/etc? – stu

0

Вы смотрели на «смотри также» раздел страницы человека для POPEN()?

Быстрый поиск google выявил эту страницу: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#blocking Говорит о блокировании и неблокирующем доступе к дескрипторам файлов.

2

Никогда не пробовал, но я не понимаю, почему вы не смогли захватить дескрипторы файла с помощью fileno(), используйте fcntl(), чтобы установить неблокирование, и используйте read()/write(). Стоит попробовать.

+0

Я сделаю это! Благодаря! – jldupont

+2

Я могу подтвердить, что эта процедура работает. – jldupont

4

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 parent process, close the writable part of the pipe */ 
      close(p[1]); 
      return p[0]; 
     default: 
      /* Close readable 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); 
    } 
} 
+0

Не должно быть: if (pipe (p) <0) return -1; ? – Aktau

+1

@Aktau Мне нравится моя версия лучше. Syscall вернет 0 при успешном завершении. Оператор if проверяет ненулевое значение. – asveikau

+1

Вы правы, ваша версия также полностью правильная, я думал о других системных вызовах! – Aktau

Смежные вопросы