2016-12-01 3 views
0

У меня есть программа, где мне нужно общаться с другой программой на ее стандартном вводе и выводе. Я могу использовать канал для отправки его ввода и перенаправления его вывода в указанный файл, который должен быть прочитан, когда это будет сделано, и это работает нормально. Я не использую pipe и dup2, потому что мне бы хотелось, чтобы моя программа хоть как-то работала как на окнах, так и на linux.popen не работает как ожидалось

Моя проблема заключается в том, что я хочу использовать трубы для передачи данных.

Я попробовал следующий фрагмент:

#include <stdio.h> 

int main() 
{ 
    while (!feof(stdin)) { 
     int x; 
     scanf("%d", &x); 
     printf("%x ", x); 
     fflush(0); 
    } 

    return 0; 
} 

в сочетании с:

#include <unistd.h> 
#include <stdio.h> 

int main() 
{ 
     int x; 
    FILE *p = popen("./test > tmp.datafile", "w"); 
    FILE *f = fopen("tmp.datafile", "r"); 

    for (int i = 0; i < 100; ++i) { 
     fprintf(p, "%d", i); 

     sleep(1); 
     x = fgetc(f); 
     printf("%c ", x); 
     fflush(0); 
    } 

    fclose(f); 
    pclose(p); 

    return 0; 
} 

Однако независимо от того, что я делаю, я просто продолжаю получать аннулирует из файла. Я подозреваю, что, возможно, есть проблемы параллелизма, в том, что я пытаюсь прочитать файл до того, как тестовый исполняемый файл завершит его очистку, однако я не знаю, как это исправить.

Есть ли лучший способ общения с программой через стандартные потоки в c?

+0

На самом деле, вы должны использовать [опрос (2)] (http://man7.org/linux/man-pages/man2/poll.2.html) в некоторых [цикл обработки событий] (https://en.wikipedia.org/wiki/Event_loop). Прочтите http://advancedlinuxprogramming.com/ и [this] (http://stackoverflow.com/a/20582916/841108) ответ. –

+0

Я не думал о опросе файла, что тоже сработает. Вы знаете, как подобный опрос окон для Linux? Я знаю, что окно popen почти идентично, но не уверен в опросе. – LambdaBeta

+0

Я вообще не знаю Windows, но некоторые библиотеки, такие как [POCO] (http://pocoproject.org/) или [Qt] (http://qt.io/) или [GLIB] (https: // developer.gnome.org/glib/stable/) (или, возможно, [libevent] (http://libevent.org/) ....) должны помогать и быть кросс-платформенными. Возможно, вам понадобятся [named pipes] (https: //en.wikipedia.org/wiki/Named_pipe) –

ответ

3

fgetc() не будет читать EOF после достижения EOF - что может произойти при первом чтении. Выполнение чего-то вроде

if(feof(f)) { 
    clearerr(f); 
    sleep(1); 
} else { 
    printf("%c ", x); 
} 

должно сортировать проблему с помощью цикла занятости.

Лучшей идеей было бы дождаться изменения файла после достижения EOF, но для этого потребуются системные вызовы.

Остерегайтесь другого состояния гонки: fopen может произойти до того, как файл был создан командой, запущенной через popen.

while(!(f = fopen(..., "r")) 
    sleep(1); 

Это еще один цикл занятости, и в целом это не очень хорошее решение, которое должно использоваться только в том случае, если dup2() недоступен.

+0

Справедливо, я не думал о том, что я читал прошлый конец. Я думаю, что сейчас я собираюсь просто поддерживать linux, а потом добавить '# ifdef' hell, чтобы попытаться поддерживать Windows. Это будет намного проще с fork, dup2, execlp. – LambdaBeta

0

Одной из проблем в вашем коде, что вы не пишете любое пустое пространство на вход p, из-за которого scanf() вызов в ./test ожидает ввода до конца так, чтобы он мог прочитать значение. Из-за чего stdout./test остается пустым. Исправить это что-то вроде этого:

fprintf(p, "%d\n", i); 

Кроме того, рекомендуется использовать небуферизованные функции ввода/вывода внутри ./test программы. printf является частью семейства функций буферизованного ввода-вывода, и вывод не может быть записан непосредственно в файл.

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 

int main() 
{ 
    while (!feof(stdin)) { 
     int x; 
     char s; 
     scanf("%d", &x); 
     sprintf(&s, "%x", x); 
     write(STDOUT_FILENO, &s, 1); 
     fflush(stdout); 
    } 

    return 0; 
}