Скачиваний:
90
Добавлен:
12.05.2015
Размер:
913.92 Кб
Скачать

13.4. Функции popen и pclose

Другим примером использования каналов является имеющаяся в стандартной библиотеке функция popen, которая создает канал и запускает другой процесс, записывающий данные в канал или считывающий их из него.

#include <stdio.h>

FILE *popen (const char *command, const char *type);

/* функция возвращает указатель FILE * в случае успешного завершения, NULL – в случае ошибки */

int pclose (FILE *stream);

/* функция возвращает код завершения команды интерпретатора, -1 – в случае ошибки */

Аргумент command представляет собой команду интерпретатора. Он обрабатывается программой sh (обычно это интерпретатор Bourne shell), поэтому для поиска исполняемого файла используется переменная PATH. Канал создается между вызывающим процессом и указанной командой. Возвращаемое функцией popen значение представляет собой обычный указатель на тип FILE, который может использоваться для ввода или для вывода в зависимости от содержимого строки type:

  • если type имеет значение “r”, вызывающий процесс считывает данные, направляемые командой command в стандартный поток вывода;

  • если type имеет значение “w”, вызывающий процесс записывает данные в стандартный поток ввода команды command.

Функция pclose закрывает стандартный поток ввода-вывода stream, созданный командой popen, ждет завершения работы программы и возвращает код завершения, принимаемый от интерпретатора.

Информацию о том, как можно реализовать функции popen и pclose, можно найти в разделе 15.3 [Раго].

Пример. В листинге 13.2 приведено еще одно решение задачи с клиентом и сервером, использующее функции popen и pclose, а также утилиту cat Unix.

Листинг 13.2. Приложение клиент-сервер с использованием popen

#include <errno.h>

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

#define MAXLINE 4096

int main(int argc, char **argv)

{

char buff[MAXLINE], command[MAXLINE];

FILE *fp;

/* чтение полного имени файла из стандартного потока ввода */

if (fgets(buff, MAXLINE, stdin) == NULL)

{

fprintf(stderr, "Клиент: ошибка чтения полного имени файла из стандартного

потока ввода\n");

exit(1);

} /* fgets() гарантирует завершающий нулевой байт */

if (buff[strlen(buff)-1] == '\n')

buff[strlen(buff)-1] = '\0';

/* удаление символа перевода строки (если есть) */

if (strlen(buff) == 0)

{

fprintf(stderr, "Клиент: введено пустое имя файла, завершение работы\n");

exit(1);

}

snprintf(command, sizeof(command), "cat %s", buff);

if ((fp = popen(command, "r")) == NULL)

{

fprintf(stderr, "Клиент: ошибка вызова функции popen: %s\n",

strerror(errno));

exit(1);

}

/* считывание из канала IPC, запись в стандартный поток вывода */

while (fgets(buff, MAXLINE, fp) != NULL)

if (fputs(buff, stdout) == EOF)

{

fprintf(stderr, "Клиент: ошибка записи в стандартный поток вывода: %s\n",

strerror(errno));

exit(1);

}

if (ferror(fp))

{

fprintf(stderr, "Клиент: ошибка чтения из канала IPC: %s\n",

strerror(errno));

exit(1);

}

pclose(fp);

exit(0);

}

Полное имя файла считывается из стандартного потока ввода, как и в программе из листинга 13.1. Затем формируется командная строка, которая передается функции popen в качестве аргумента. Вывод командного интерпретатора или команды cat копируется в стандартный поток вывода.

Одним из отличий этой реализации от приведенной в листинге 13.1 является отсутствие возможности формировать собственные сообщения об ошибках. Теперь мы целиком зависим от программы cat, которая, впрочем, в ОС Linux выводит вполне информативные сообщения об ошибках. Программа cat записывает сообщение об ошибке в стандартный поток вывода сообщений об ошибках (stderr), а файловый указатель fp, возвращаемый функцией popen, с этим потоком не связан, потому что к созданному каналу подключен только стандартный поток вывода (stdout).

Соседние файлы в папке Chapter.4