2009-11-14 13 views

Odpowiedz

25

Instalator tak:

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

Teraz można przeczytać:

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

Kiedy” gotowe, oczyszczenie:

pclose(f); 
+0

Działa pięknie ... dzięki! – jldupont

+0

potok, będący wskaźnikiem PLIKU, jest z natury zbuforowany, czy istnieje pewność, że za pomocą deskryptora pliku bezpośrednio nie przeoczysz czegoś, co zostało wciągnięte do bufora plików, czy może to być zagwarantowane tak długo, jak długo będziesz Najpierw wywołasz fget/fread/etc? – stu

2

Nigdy tego nie próbowałem, ale nie rozumiem, dlaczego nie można było pobrać deskryptorów plików za pomocą funkcji fileno(), użyj funkcji fcntl(), aby ustawić opcję bez blokowania, i użyj funkcji read()/write(). Warte spróbowania.

+0

Zrobię to! Dzięki! – jldupont

+2

Mogę potwierdzić, że ta procedura działa. – jldupont

4

popen() wywołuje wewnętrznie pipe(), fork(), dup2() (do punktu FDS procesu podrzędnego 0/1/2 do rur) i execve(). Czy zastanawiałeś się nad ich użyciem? W takim przypadku można ustawić odczytaną rurę jako nieblokującą za pomocą fcntl().

aktualizacja: Oto przykład, tylko w celach poglądowych:

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

Nie powinno to być: if (pipe (p) <0) return -1; ? – Aktau

+1

@Aktau Bardziej podoba mi się moja wersja. Syscall zwróci 0 po pomyślnym zakończeniu. Instrukcja if jest niezerowa. – asveikau

+1

Masz rację, twoja wersja jest całkowicie poprawna, myślałem o innych systemach! – Aktau