Чтение онлайн

на главную - закладки

Жанры

Основы программирования в Linux
Шрифт:

Итак, как же

dup
помогает в обмене данными между процессами? Хитрость кроется в знании того, что дескриптор стандартного файла ввода всегда 0 и что
dup
всегда возвращает новый файловый дескриптор, применяя наименьший доступный номер. Сначала закрыв дескриптор 0, а затем вызвав
dup
, вы получите новый файловый дескриптор с номером 0. Поскольку новый файловый дескриптор — это дубликат существующего, стандартный ввод изменится и получит доступ к файлу или каналу, файловый дескриптор которого вы передали в функцию
dup
. В результате вы создадите два файловых дескриптора, которые ссылаются на один и тот же файл или канал и один из них будет стандартным вводом.

Управление файловым дескриптором с помощью close и dup

Легче всего понять, что происходит, когда вы закрываете файловый дескриптор 0 и затем вызываете

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

Таблица 13.1

Номер файлового дескриптора Первоначально После закрытия файлового дескриптора 0 После вызова
dup
0 Стандартный ввод {closed} Файловый дескриптор канала
1 Стандартный вывод Стандартный вывод Стандартный вывод
2 Стандартный поток ошибок Стандартный поток ошибок Стандартный поток ошибок
3 Файловый дескриптор канала Файловый дескриптор канала Файловый дескриптор канала

А теперь выполните упражнение 13.8.

Упражнение 13.3. Каналы и
dup

Давайте вернемся к предыдущему примеру, но на этот раз вы измените дочернюю программу, заменив в ней файловый дескриптор stdin концом считывания

read
созданного вами канала. Вы также выполните некоторую реорганизацию файловых дескрипторов, чтобы дочерняя программа могла правильно определить конец данных в канале. Как обычно, мы пропустили некоторые проверки ошибок для краткости.

Превратите программу pipe3.c в pipe5.c с помощью следующего программного кода:

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int main {

 int data_processed;

 int file pipes[2];

 const char some_data[] = "123";

 pid_t fork_result;

 if (pipe(file_pipes) == 0) {

fork_result = fork;

if (fork_result == (pid_t)-1) {

fprintf(stderr, "Fork failure");

exit(EXIT_FAILURE);

}

if (fork_result == (pid_t)0) {

close(0);

dup(file_pipes[0];

close(file_pipes[0]);

close(file_pipes[1]);

execlp("od", "od", "-c", (char*)0);

exit(EXIT_FAILURE);

} else {

close(file_pipes[0]);

data_processed = write(file_pipes[1], some_data,

strlen(some_data));

close(file_pipes[1]);

printf("%d — wrote %d bytes\n", (int)getpid, data_processed);

}

 }

 exit(EXIT_SUCCESS);

}

У этой программы следующий вывод:

$ ./pipe5

22495 - wrote 3 bytes

0000000 1 2 3

0000003

Как это работает

Как и прежде, программа создает канал, затем выполняет вызов

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

Давайте первым рассмотрим дочерний процесс. Он закрывает свой стандартный ввод с помощью

close(0)
и затем вызывает
dup(file_pipes[0])
. Этот вызов дублирует файловый дескриптор, связанный с концом
read
канала, как файловый дескриптор 0, стандартный ввод. Далее дочерний процесс закрывает исходный файловый дескриптор для чтения из канала,
file_pipes[0]
. Поскольку этот процесс никогда не будет писать в канал, он также закрывает файловый дескриптор для записи в канал,
file_pipes[1]
. Теперь у дочернего процесса единственный файловый дескриптор, связанный с каналом, файловый дескриптор 0, его стандартный ввод.

Далее дочерний процесс может применить

exec
для вызова любой программы, которая читает стандартный ввод. В данном случае мы используем команду
od
. Команда
od
будет ждать, когда данные станут ей доступны, как если бы она ждала ввода с терминала пользователя. В действительности без специального программного кода, позволяющего непосредственно выяснить разницу, она не будет знать, что ввод приходит из канала, а не с терминала.

Родительский процесс начинает с закрытия конца чтения канала,

file_pipes[0]
, потому что он никогда не будет читать из канала. Затем он пишет данные в канал. Когда все данные записаны, родительский процесс закрывает конец записи в канал и завершается. Поскольку теперь нет файловых дескрипторов, открытых для записи в канал, программа
od
сможет считать три байта, записанных в канал, но последующие операции чтения далее будут возвращать 0 байтов, указывая на конец файла. Когда
read
вернет 0, программа
od
завершится. Это аналогично выполнению команды
od
, введенной с терминала, и последующему нажатию комбинации клавиш <Ctrl>+<D> для отправки признака конца файла команде
od
.

На рис. 13.3 показан результат вызова

pipe
, на рис. 13.4 — результат вызова
fork
, а на рис. 13.5 представлена программа, когда она готова к передаче данных.

Рис. 13.3

Рис. 13.4

Рис. 13.5

Именованные каналы: FIFO

Поделиться:
Популярные книги

Первый среди равных

Бор Жорж
1. Первый среди Равных
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Первый среди равных

Леший

Северский Андрей
1. Леший в "Городе гоблинов"
Фантастика:
рпг
5.00
рейтинг книги
Леший

Сокрушитель

Поселягин Владимир Геннадьевич
3. Уникум
Фантастика:
боевая фантастика
5.60
рейтинг книги
Сокрушитель

Снайпер

Поселягин Владимир Геннадьевич
3. Жнец
Фантастика:
боевая фантастика
попаданцы
5.60
рейтинг книги
Снайпер

Сын Петра. Том 1. Бесенок

Ланцов Михаил Алексеевич
1. Сын Петра
Фантастика:
попаданцы
альтернативная история
6.80
рейтинг книги
Сын Петра. Том 1. Бесенок

Идеальный мир для Лекаря 12

Сапфир Олег
12. Лекарь
Фантастика:
боевая фантастика
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 12

Индульгенция 2. Без права на жизнь

Машуков Тимур
2. Темный сказ
Фантастика:
аниме
фэнтези
попаданцы
гаремник
5.00
рейтинг книги
Индульгенция 2. Без права на жизнь

Тихие ночи

Владимиров Денис
2. Глэрд
Фантастика:
фэнтези
боевая фантастика
попаданцы
5.00
рейтинг книги
Тихие ночи

Идеальный мир для Демонолога 9

Сапфир Олег
9. Демонолог
Фантастика:
боевая фантастика
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Демонолога 9

Убийца

Бубела Олег Николаевич
3. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.26
рейтинг книги
Убийца

Мастер 7

Чащин Валерий
7. Мастер
Фантастика:
фэнтези
боевая фантастика
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Мастер 7

Кодекс Крови. Книга ХIV

Борзых М.
14. РОС: Кодекс Крови
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Крови. Книга ХIV

Второгодка. Книга 3. Ученье свет

Ромов Дмитрий
3. Второгодка
Фантастика:
городское фэнтези
сказочная фантастика
альтернативная история
5.00
рейтинг книги
Второгодка. Книга 3. Ученье свет

Древесный маг Орловского княжества 4

Павлов Игорь Васильевич
4. Орловское княжество
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Древесный маг Орловского княжества 4