UNIX: разработка сетевых приложений
Часть 173 из 399 Информация о книге
Родительский процесс в ожидании завершения дочернего процессаРодительский процесс закрывает другой конец потокового канала и вызывает функцию17-22для ожидания завершения дочернего процесса. Статус завершения дочернего процесса возвращается в переменнойwaitpid, и сначала мы проверяем, что программа завершилась нормально (то есть не была завершена из-за возникновения какого-либо сигнала). Затем макросstatusпреобразует статус завершения в статус выхода, значение которого должно быть между 0 и 255. Мы вскоре увидим, что если при открытии необходимого файла программойWEXITSTATUSпроисходит ошибка, то эта программа завершается, причем статус ее завершения равен соответствующему значению переменнойopenfile.errnoПолучение дескриптораНаша функция23, которую мы показываем в следующем листинге, получает дескриптор потокового канала. Кроме получения дескриптора мы считываем 1 байт данных, но ничего с этими данными не делаем.read_fdПРИМЕЧАНИЕПри отправке и получении дескриптора по потоковому каналу мы всегда отправляем как минимум 1 байт данных, даже если получатель никак эти данные не обрабатывает. Иначе получатель не сможет распознать, что значит нулевое возвращаемое значение из функции read_fd: отсутствие данных (но, возможно, есть дескриптор) или конец файла.
В листинге 15.9 показана функция
, вызывающая функциюreadfdдля получения данных и дескриптора через доменный сокет Unix. Первые три аргумента этой функции те же, что и для функцииrecvmsg, а четвертый (read) является указателем на целое число. После выполнения этой функцииrecvfdбудет указывать на полученный дескриптор.recvfdЛистинг 15.9. Функция read_fd: получение данных и дескриптора
//lib/read_fd.c1 #include "unp.h"2 ssize_t3 read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)4 {5 struct msghdr msg;6 struct iovec iov[1];7 ssize_t n;8 int newfd;9 #ifdef HAVE_MSGHDR_MSG_CONTROL10 union {11 struct cmsghdr cm;12 char control[CMSG_SPACE(sizeof(int))];13 } control_un;14 struct cmsghdr *cmptr;15 msg.msg_control = control_un.control;16 msg.msg_controllen = sizeof(control_un.control);17 #else18 msg.msg_accrights = (caddr_t)&newfd;19 msg.msg_accrightslen = sizeof(int);20 #endif21 msg.msg_name = NULL;22 msg.msg_namelen = 0;23 iov[0].iov_base = ptr;24 iov[0].iov_len = nbytes;25 msg.msg_iov = iov;26 msg.msg_iovlen = 1;27 if ((n = recvmsg(fd, &msg, 0)) <= 0)28 return (n);29 #ifdef HAVE_MSGHDR_MSG_CONTROL30 if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&31 mptr->cmsg_len == CMSG_LEN(sizeof(int))) {32 if (cmptr->cmsg_level != SOL_SOCKET)33 err_quit("control level != SOL_SOCKET");34 if (cmptr->cmsg_type != SCM_RIGHTS)35 err_quit("control type != SCM_RIGHTS");36 *recvfd = *((int*)CMSG_DATA(cmptr));37 } else38 *recvfd = -1; /* дескриптор не был передан */39 #else40 if (msg.msg_accrightslen == sizeof(int))41 *recvfd = newfd;42 else43 *recvfd = -1; /* дескриптор не был передан */44 #endif45 return (n);46 }Эта функция должна работать с обеими версиями функции8-26: с элементомrecvmsgи с элементомmsg_control. Наш заголовочный файлmsg_accrights(см. листинг Г.2) определяет константуconfig.h, если поддерживается версия функцииHAVE_MSGHDR_MSG_CONTROLсrecvmsg.msg_controlПроверка выравнивания буфера msg_controlБуфер10-13должен быть выровнен в соответствии со структуройmsg_control. Просто выделить в памяти массив типаmsghdrнедостаточно. Здесь мы объявляем объединение, состоящее из структурыcharи символьного массива, что гарантирует необходимое выравнивание массива. Возможно и другое решение — вызвать функциюcmsghdr, но это потребует освобождения памяти перед завершением функции.mallocВызывается функция27-45. Если возвращаются вспомогательные данные, их формат будет таким, как показано на рис. 14.4. Мы проверяем, верны ли длина, уровень и тип, затем получаем вновь созданный дескриптор и возвращаем его через указатель вызывающего процессаrecvmsg. Макросrecvfdвозвращает указатель на элементCMSG_DATAобъекта вспомогательных данных как указатель на элемент типаcmsg_data. Мы преобразуем его к указателю на элемент типаunsigned charи получаем целочисленный дескриптор, на который указывает этот указатель.int