Вход/Регистрация
Разработка приложений в среде Linux. Второе издание
вернуться

Троан Эрик В.

Шрифт:

#include <unistd.h>

int dup2(int oldfd, int newfd);

Если

newfd
ссылается на уже открытый дескриптор, то он закрывается. Если вызов завершен успешно, он возвращает новый файловый дескриптор и
newfd
ссылается на тот же файл, что
oldfd
. Системный вызов
fcntl
представляет почти ту же функциональность командой
F_DUPFD
. Первый аргумент —
fd
— это уже открытый файловый дескриптор. Новый файловый дескриптор — это первый доступный дескриптор, равный или больший, чем значение последнего аргумента
fcntl
. (В этом состоит отличие от работы
dup2
.) Вы можете реализовать
dup2
через
fcntl
следующим образом.

int dup2(int oldfd, int newfd) {

 close(newfd); /* ensure new fd is available */

 return fcntl(oldfd, F_DUPFD, newfd);

}

Создание двух файловых дескрипторов, ссылающихся на один и тот же файл — это не то же самое, что открытие файла дважды. Почти все атрибуты дублированных дескрипторов разделяются: они разделяют текущую позицию, режим доступа и блокировки. (Все это записывается в файловой структуре [50] , которая создается при каждом открытии файла. Файловый дескриптор ссылается на файловую структуру, и дескриптор, возвращенный

dup
, ссылается на одну и ту же структуру.) Единственный атрибут, который может независимо управляться в этих двух дескрипторах — это состояние "закрыть при выполнении". После того, как процесс вызывает
fork
, то файлы, открытые в родительском процессе, наследуются дочерним, и эти пары файловых дескрипторов (один в родительском процессе, другой — в дочернем) ведут себя так, будто файловые дескрипторы были дублированы с текущей позицией и другими разделенными атрибутами [51] .

50

В зависимости от операционной системы, файловые структуры также известны как позиции в таблице файлов или объекты открытых файлов.

51

Файловый дескриптор в каждом процессе ссылается на одну и ту же файловую структуру.

11.6. Создание неименованных каналов

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

Оболочки применяют неименованные каналы для выполнения команд вроде

ls | head
. Процесс
ls
пишет в тот канал, из которого
head
читает свой ввод, выдавая ожидаемый пользователем результат.

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

#include <unistd.h>

int pipe(int fds[2]);

Единственный параметр-массив включает два файловых дескриптора —

fd[0]
для чтения и
fd[1]
для записи.

11.7. Добавление перенаправления для ladsh

Теперь, когда мы рассмотрели основные манипуляции с файлами, мы можем научить

ladsh
перенаправлению ввода и вывода через файлы и каналы.
ladsh2.с
, который мы представим здесь, работает с каналами (описанными символом
|
в командах
ladsh
, как это делается в большинстве командных оболочек) и перенаправление ввода и вывода в файловые дескрипторы. Мы покажем только модифицированные части кода здесь — полный исходный текст
ladsh2.с
доступен по упомянутым в начале книги адресам. Изменения в
parseCommand
— это простое упражнение по разбору строк, поэтому мы не будем надоедать дискуссией об этом.

11.7.1. Структуры данных

Хотя код в

ladsh1.с
поддерживает концепцию задания как множества процессов (предположительно, объединенных вместе каналами), он не предоставляет способа указания того, какие файлы использовать для ввода и вывода. Чтобы позволить это, добавляются новые структуры данных и модифицируются существующие.

24: REDIRECT_APPEND};

25:

26: struct redirectionSpecifier {

27: enum redirectionTypetype; /* тип перенаправления */

28: int fd; /*перенаправляемый файловый дескриптор*/

29: char * filename; /* файл для перенаправления fd */

30: };

31:

32: struct childProgram {

33: pid_t pid; /* 0 если завершен */

34: char **argv; /* имя программы и аргументы */

35: int numRedirections; /* элементы в массиве перенаправлений */

36: struct redirectionSpecifier *redirections; /* перенаправления ввода-вывода*/

37: } ;

Структура

struct redirectionSpecifier
сообщает
ladsh2.с
о том, как установить отдельный файловый дескриптор. Она содержит
enum redirectionTypetype
, который указывает, является ли это перенаправление перенаправлением ввода, перенаправлением вывода, который должен быть добавлен к существующему файлу, либо перенаправлением вывода, которое заменяет существующий файл. Она также включает перенаправляемый файловый дескриптор и имя файла. Каждая дочерняя программа (
struct childProgram
) теперь специфицирует нужное ей количество перенаправлений.

Эти новые структуры данных не связаны с установкой каналов между процессами. Поскольку задание определено как множество дочерних процессов с каналами, связывающими их, нет необходимости в более подробной информации, описывающей каналы. На рис. 11.1 показано, как эти новые структуры должны выглядеть для команды

tail < input-file | sort > output-file
.

Рис. 11.1. Структуры данных, описывающие задание для

ladsh2.с

  • Читать дальше
  • 1
  • ...
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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