Шрифт:
Функция
my_open
, показанная в листинге 15.8, должна выглядеть для вызывающего процесса как обычная функция Unix open
. Она получает два аргумента — полное имя и режим открытия (например, O_RDONLY
обозначает, что файл доступен только для чтения), открывает файл и возвращает дескриптор. Листинг 15.8. Функция my_open: открытие файла и возвращение дескриптора
//unixdomain/myopen.c
1 #include "unp.h"
2 int
3 my_open(const char *pathname, int mode)
4 {
5 int fd, sockfd[2], status;
6 pid_t childpid;
7 char c, argsockfd[10], argmode[10];
8 Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
9 if ((childpid = Fork) == 0) { /* дочерний процесс */
10 Close(sockfd[0]);
11 snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);
12 snprintf(argmode, sizeof(argmode), "%d", mode);
13 execl("./openfile", "openfile", argsockfd, pathname, argmode,
14 (char*)NULL);
15 err_sys("execl error");
16 }
17 /* родительский процесс - ожидание завершения дочернего процесса */
18 Close(sockfd[1]); /* закрываем конец, который мы не используем */
19 Waitpid(childpid, &status, 0);
20 if (WIFEXITED(status) == 0)
21 err_quit("child did not terminate");
22 if ((status = WEXITSTATUS(status)) == 0)
23 Read_fd(sockfd[0], &c, 1, &fd);
24 else {
25 errno = status; /* установка значения errno в статус дочернего
процесса */
26 fd = -1;
27 }
28 Close(sockfd[0]);
29 return (fd);
30 }
Создание потокового канала
8
Функция socketpair
создает потоковый канал. Возвращаются два дескриптора: sockfd[0]
и sockfd[1]
. Это состояние, которое мы показали на рис. 15.1. Функции fork и exec
9-16
Вызывается функция fork
, после чего дочерний процесс закрывает один конец потокового канала. Номер дескриптора другого конца потокового канала помещается в массив argsockfd
, а режим открытия помещается в массив argmode
. Мы вызываем функцию snprintf
, поскольку аргументы функции exec должны быть символьными строками. Выполняется программа openfile
. Функция execl
возвращает управление только в том случае, если она встретит ошибку. При удачном выполнении начинает выполняться функция main
программы openfile
. Родительский процесс в ожидании завершения дочернего процесса
17-22
Родительский процесс закрывает другой конец потокового канала и вызывает функцию waitpid
для ожидания завершения дочернего процесса. Статус завершения дочернего процесса возвращается в переменной status
, и сначала мы проверяем, что программа завершилась нормально (то есть не была завершена из-за возникновения какого-либо сигнала). Затем макрос WEXITSTATUS
преобразует статус завершения в статус выхода, значение которого должно быть между 0 и 255. Мы вскоре увидим, что если при открытии необходимого файла программой openfile
происходит ошибка, то эта программа завершается, причем статус ее завершения равен соответствующему значению переменной errno
. Получение дескриптора
23
Наша функция read_fd
, которую мы показываем в следующем листинге, получает дескриптор потокового канала. Кроме получения дескриптора мы считываем 1 байт данных, но ничего с этими данными не делаем. ПРИМЕЧАНИЕ
При отправке и получении дескриптора по потоковому каналу мы всегда отправляем как минимум 1 байт данных, даже если получатель никак эти данные не обрабатывает. Иначе получатель не сможет распознать, что значит нулевое возвращаемое значение из функции read_fd: отсутствие данных (но, возможно, есть дескриптор) или конец файла.