2009-11-14 7 views

Répondre

25

installation comme ceci:

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

Maintenant, vous pouvez lire:

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

Lorsque vous » re fait, nettoyage:

pclose(f); 
+0

Fonctionne magnifiquement ... merci! – jldupont

+0

le pipe, étant un pointeur FILE, est intrinsèquement tamponné, il n'y a aucune assurance qu'en utilisant le descripteur de fichier directement vous ne manquerez pas quelque chose qui a été tiré dans le tampon de fichier, ou peut-il être garanti aussi longtemps que vous N'appelez pas fget/fread/etc en premier? – stu

2

Je ne l'ai jamais essayé mais je ne vois pas pourquoi vous n'avez pas pu récupérer les descripteurs de fichier avec fileno(), utilisez fcntl() pour définir non-bloquant, et utilisez read()/write(). Ça vaut le coup d'essayer.

+0

Je vais faire ça! Merci! – jldupont

+2

Je peux confirmer que cette procédure fonctionne. – jldupont

4

popen() appelle en interne pipe(), fork(), dup2() (pour pointer les fds de processus enfant 0/1/2 aux tuyaux) et execve(). Avez-vous envisagé de les utiliser à la place? Dans ce cas, vous pouvez définir le canal que vous avez lu comme non bloquant à l'aide de fcntl().

mise à jour: Voici un exemple, juste à titre d'exemple:

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

Cela ne devrait pas être: if (pipe (p) <0) renvoie -1; ? – Aktau

+1

@Aktau J'aime mieux ma version. Le syscall retournera 0 en cas de succès. L'instruction if teste pour non zéro. – asveikau

+1

vous avez raison, votre version est aussi complètement correcte, je pensais à d'autres syscalls! – Aktau