Программа, представленная в листинге 5.8, с помощью функции dup2()
соединяет выходной. Конец канала со входом команды sort
. [16] Команда sort читает строки текста ил стандартного входного потока, сортирует их в алфавитном порядке и записывает в стандартный выходной поток.
После создания канала программа "делится" функцией fork()
на два процесса. Родительский процесс записывает в канал различные строки, а дочерний процесс соединяет выходной конец канала со своим входным потоком, после чего запускает команду sort
.
Листинг 5.8. ( dup2.c ) Перенаправление выходного потока канала с помощью функции dup2()
#include
#include
#include
#include
int main() {
int fds[2];
pid_t pid;
/* Создание канала. Дескрипторы обоих концов канала
помещаются в массив FDS. */
pipe (fds);
/* Создание дочернего процесса. */
pid = fork();
if (pid == (pid_t)0) {
/* Это дочерний процесс. Закрываем копию входного конца
канала */
close(fds[1]);
/* Соединяем выходной конец канала со стандартным входным
потоком. */
dup2(fds[0], STDIN_FILENO);
/* Замещаем дочерний процесс программой sort. */
execlp("sort", "sort", 0);
} else {
/* Это родительский процесс. */
FILE* stream;
/* Закрываем копию выходного конца канала. */
close(fds[0]);
/* Приводим дескриптор входного конца канала к типу FILE*
и записываем данные в канал. */
stream = fdopen(fds[1], "w");
fprintf(stream, "This is a test.\n");
fprintf(stream, "Hello, world.\n");
fprintf(stream, "My dog has fleas.\n");
fprintf(stream, "This program is great.\n");
fprintf(stream, "One fish, two fish.\n");
fflush(stream);
close(fds[1]);
/* Дожидаемся завершения дочернего процесса. */
waitpid(pid, NULL, 0);
}
return 0;
}
5.4.4. Функции popen() и pclose()
Каналы часто используются для передачи данных программе, выполняющейся как подпроцесс (или приема данных от нее). Специально для этих целей предназначены функции popen()
и pclose()
, устраняющие необходимость в вызове функций pipe()
, dup2()
, exec()
и fdopen()
.
Сравните листинг 5.9 с предыдущим примером (листинг 5.8).
Листинг 5.9. ( popen.c ) Использование функций popen()
и pclose()
#include
#include
int main() {
FILE* stream = popen("sort", "w");
fprintf(stream, "This is a test.\n");
fprintf(stream, "Hello, world.\n");
fprintf(stream, "My dog has fleas\n");
fprintf(stream, "This program is great.\n");
fprintf(stream, "One fish, two fish.\n");
return pclose(stream);
}
Функция popen()
создает дочерний процесс, в котором выполняется команда sort
. Один этот вызов заменяет вызовы функций pipe()
, fork()
, dup2()
и execlp()
. Второй аргумент, "w"
, указывает на то, что текущий процесс хочет осуществлять запись в дочерний процесс. Функция popen()
возвращает указатель на один из концов канала; второй конец соединяется со стандартным входным потоком дочернего процесса. Функция pclose()
закрывает входной поток дочернего процесса, дожидается его завершения и возвращает код статуса.
Первый аргумент функции popen()
является командой интерпретатора, выполняемой в подпроцессе /bin/sh
. Интерпретатор просматривает переменную среды PATH
, чтобы определить, где следует искать команду. Если второй аргумент равен "r"
, функция возвращает указатель на стандартный выходной поток дочернего процесса, чтобы программа могла читать данные из него. Если второй аргумент равен "w"
, функция возвращает указатель на стандартный входной поток дочернего процесса, чтобы программа могла записывать данные в него. В случае ошибки возвращается пустой указатель.
Функция pclose()
закрывает поток, указатель на который был возвращен функцией popen()
, и дожидается завершения дочернего процесса.
Файл FIFO (First-In, First-Out — первым пришел, первым обслужен) — это канал, у которого есть имя в файловой системе. Любой процесс может открыть и закрыть такой файл. Процессы, находящиеся на противоположных концах канала, не обязаны быть связанными друг с другом. FIFO-файлы называют именованными каналами .
FIFO-файл создается с помощью команды mkfifo
. Путь к файлу указывается в командной строке, например:
% mkfifo /tmp/fifo
% ls -l /tmp/fifo
prw-rw-rw- 1 samuel users 0 Jan 16 14:04 /tmp/fifo
Читать дальше