□ стандартный вывод cmd2
подсоединен к экрану терминала.
На самом деле командная оболочка заново соединила потоки стандартных ввода и вывода так, что потоки данных проходят с клавиатурного ввода через две команды и выводятся на экран. На рис. 13.1 приведено визуальное представление этого процесса.
Рис. 13.1
В этой главе вы увидите, как достичь этого эффекта в программе и как можно использовать каналы для связи многих процессов, что позволит создать простую клиент-серверную систему.
Возможно, простейший способ передачи данных между программами — применение функций popen
и pclose
. У них следующие прототипы:
#include
FILE *popen(const char *command, const char *open_mode);
int pclose(FILE *stream_to_close);
Функция popen позволяет программе запустить другую программу как новый процесс и либо передать ей данные, либо получить их из нее. Строка command
— это имя программы для выполнения вместе с любыми параметрами, параметр open_mode
должен быть "r"
или "w"
.
Если open_mode
— "r"
, вывод вызванной программы становится доступен вызывающей программе и может быть считан из возвращаемого функцией popen
файлового потока FILE*
с помощью обычных функций библиотеки stdio, предназначенных для чтения (например, fread
). Но если open_mode
— "w"
, программа может отправить данные вызванной команде с помощью вызова функции fwrite
. Далее вызванная программа сможет читать данные из своего стандартного ввода. Обычно вызванная программа не знает, что она считывает данные из другого процесса; она просто читает свой поток стандартного ввода и воздействует на него.
Вызов функции popen
должен задавать "r"
или "w"
; никакого другого значения стандартной реализацией popen не поддерживается. Это означает, что вы не можете вызвать другую программу и одновременно читать из нее и писать в нее. В случае сбоя popen
возвращает пустой указатель. Если вы хотите создать двунаправленную связь с помощью каналов, стандартное решение — применить два канала: по одному для потока данных каждого направления.
Когда процесс, стартовавший с помощью popen
, закончится, вы можете закрыть файловый поток, связанный с ним, с помощью функции pclose
. Вызов pclose
вернет управление, только когда процесс, запущенный с помощью popen
, завершится. Если он все еще выполняется во время вызова pclose
, вызов pclose
будет ждать окончания процесса.
Функция pclose
обычно возвращает код завершения процесса, чей файловый поток она закрывает. Если вызывающий процесс уже выполнил оператор wait
перед вызовом pclose
, статус завершения будет потерян, поскольку вызванный процесс закончен, и функция pclose
вернет -1 с переменной errno
, получившей значение ECHILD
.
Выполните упражнение 13.1.
Упражнение 13.1. Чтение вывода внешней программы
Давайте опробуем простой пример popen1.c с функциями popen
и pclose
. Вы будете применять в программе popen
для доступа к информации из uname
. uname
— это команда, выводящая системную информацию, включая тип компьютера, имя ОС, версию и выпуск, а также сетевое имя машины.
Запустив программу, вы откроете канал к uname
; сделаете его читаемым и зададите read_fp
, как указатель на вывод. В конце канал, на который указывает read_fp
, закрывается.
#include
#include
#include
#include
int main() {
FILE *read_fp;
char buffer[BUFSIZ +1];
int chars_read;
memset(buffer, '\0', sizeof(buffer));
read_fp = popen("uname -a", "r");
if (read_fp ! = NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
if (chars_read > 0) {
printf("Output was:-\n%s\n", buffer);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
Когда вы выполните программу, то должны получить вывод, похожий на следующий (полученный на одной из машин авторов):
Читать дальше