2009-11-14 13 views

risposta

25

Setup in questo modo:

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

Ora si può leggere:

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

Quando si' fatto, pulizia:

pclose(f); 
+0

Funziona magnificamente ... grazie! – jldupont

+0

la pipa, essendo un puntatore FILE, è intrinsecamente bufferizzata, c'è la certezza che usando il descrittore di file direttamente non si perderà qualcosa che è stato inserito nel buffer dei file, o può essere garantito fino a quando non si chiamare prima fget/fread/etc prima? – stu

2

Mai provato, ma non vedo perché non è possibile afferrare i descrittori di file con fileno(), utilizzare fcntl() per impostarlo su non-blocking e usare read()/write(). Vale la pena provare.

+0

Lo farò! Grazie! – jldupont

+2

Posso confermare che questa procedura funziona. – jldupont

4

popen() chiama internamente pipe(), fork(), dup2() (per puntare FDS del processo figlio 0/1/2 ai tubi) e execve(). Hai preso in considerazione l'utilizzo di questi invece? In tal caso, puoi impostare la pipe che hai letto per non bloccare usando fcntl().

aggiornamento: Ecco un esempio, solo a scopo illustrativo:

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

Non dovrebbe essere: if (pipe (p) <0) return -1; ? – Aktau

+1

@Aktau Mi piace la mia versione migliore. Syscall restituirà 0 in caso di successo. L'istruzione if verifica per i non zero. – asveikau

+1

hai ragione, la tua versione è anche completamente corretta, stavo pensando ad altre syscalls! – Aktau