2016-04-12 2 views
2

Написал небольшой скрипт для работы с php5-cgi с использованием fork(), exec() и труб. Скрипт работает хорошо, когда вывод php5-cgi мал. Но когда он значительно большой (при использовании <?php phpinfo(); ?> во входном файле), он ничего не возвращает.Труба C не работает с большими записями

#include<netinet/in.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<sys/socket.h> 
#include<sys/stat.h> 
#include<sys/types.h> 
#include<unistd.h> 
#include<fcntl.h> 

int main(int argc, char const *argv[]) { 

    int status; 
    int link[2]; 
    char out[4096]; 
    char * arg[3]={"php5-cgi","a.php",0}; 
    if (pipe(link)==-1){ 
    perror("pipe"); 
    } 
    int pid=fork(); 
    if (!pid){ 
    dup2 (link[1], 1); 
    close(link[0]); 
    execvp("php5-cgi", arg); 
    } else { 
    waitpid(pid, &status,0); 
    close(link[1]); // parent doesn't write 
     char reading_buf[1]; 
     while(read(link[0], reading_buf, 1) > 0){ 
      write(1, reading_buf, 1); 
     } 
     close(link[0]); 
    } 
    printf("%s\n", "end"); 
    return 0; 
} 

Я предполагаю, что это связано с переполнением трубы. Есть ли способ исправить эту проблему? Или есть какие-то альтернативы для работы с большим выводом?

+0

Разделить данные, которые вы пишете на более мелкие куски? –

+2

Первое, что нужно сделать, всегда: проверить возвращаемые значения всех ваших системных вызовов. –

ответ

5

Буфер для буфера относительно невелик, обычно несколько килобайт. Ребенок может писать до тех пор, пока буфер не будет заполнен; то дальнейшие записи будут блокироваться до тех пор, пока не будут прочитаны некоторые данные.

Ваш родитель звонит waitpid, прежде чем пытаться читать из трубы. Поэтому он ждет, пока ребенок закончит. Но если ребенок заблокирован, пытаясь написать, он никогда не прекратится. Таким образом, вы никогда не преодолеете waitpid в этом случае.

Что вы, вероятно, захотите сделать, это переместить waitpid после цикла read/write. Затем ребенок может продолжать писать больше данных по мере его чтения. Когда read(), наконец, терпит неудачу, это, скорее всего, потому, что ребенок вышел и закрыл свой конец трубы. Таким образом, вы можете сделать waitpid в это время, чтобы получить статус выхода и пожинать зомби.

Также проверьте возвращаемые значения всех ваших системных вызовов! И скомпилируйте с предупреждениями (это предупредит вас, что вы забыли #include <sys/wait.h>).

+0

Работает '' waitpid'''! Но это означает, что нет гарантии, что я получу весь вывод от exec до родительского потока. Я прав? – paarandika

+0

@paarandika: Нет, не правильно. Вы получите весь результат. Почему вы думаете, что не хотите? 'Read' в родительском будет читать из буфера, но если он станет пустым,' read' будет блокироваться, пока ребенок еще не напишет. Однако, если буфер пуст и ребенок закрыл трубу или выйдет, 'read' прекратит блокировку и вернет 0. Таким образом, ваш цикл не будет завершен до тех пор, пока все данные, написанные дочерним элементом, не будут прочитаны. –

+0

Я подумал, что когда пустая труба, чтение возвращается, хотя ребенок не закрыл трубку. BTW в конце дочернего процесса, автоматически ли закрывается труба? Потому что в моем коде у меня нет шансов закрыть его. – paarandika

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