-->

UNIX: разработка сетевых приложений

На нашем литературном портале можно бесплатно читать книгу UNIX: разработка сетевых приложений, Стивенс Уильям Ричард-- . Жанр: ОС и Сети. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале bazaknig.info.
UNIX: разработка сетевых приложений
Название: UNIX: разработка сетевых приложений
Дата добавления: 16 январь 2020
Количество просмотров: 389
Читать онлайн

UNIX: разработка сетевых приложений читать книгу онлайн

UNIX: разработка сетевых приложений - читать бесплатно онлайн , автор Стивенс Уильям Ричард

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

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала

Перейти на страницу:
Родительский процесс в ожидании завершения дочернего процесса

17-22
 Родительский процесс закрывает другой конец потокового канала и вызывает функцию
waitpid
для ожидания завершения дочернего процесса. Статус завершения дочернего процесса возвращается в переменной
status
, и сначала мы проверяем, что программа завершилась нормально (то есть не была завершена из-за возникновения какого-либо сигнала). Затем макрос
WEXITSTATUS
преобразует статус завершения в статус выхода, значение которого должно быть между 0 и 255. Мы вскоре увидим, что если при открытии необходимого файла программой
openfile
происходит ошибка, то эта программа завершается, причем статус ее завершения равен соответствующему значению переменной
errno
.

Получение дескриптора

23
 Наша функция
read_fd
, которую мы показываем в следующем листинге, получает дескриптор потокового канала. Кроме получения дескриптора мы считываем 1 байт данных, но ничего с этими данными не делаем.

ПРИМЕЧАНИЕ

При отправке и получении дескриптора по потоковому каналу мы всегда отправляем как минимум 1 байт данных, даже если получатель никак эти данные не обрабатывает. Иначе получатель не сможет распознать, что значит нулевое возвращаемое значение из функции read_fd: отсутствие данных (но, возможно, есть дескриптор) или конец файла.

В листинге 15.9 показана функция

readfd
, вызывающая функцию
recvmsg
для получения данных и дескриптора через доменный сокет Unix. Первые три аргумента этой функции те же, что и для функции
read
, а четвертый (
recvfd
) является указателем на целое число. После выполнения этой функции
recvfd
будет указывать на полученный дескриптор.

Листинг 15.9. Функция read_fd: получение данных и дескриптора

//lib/read_fd.c

 1 #include "unp.h"

 2 ssize_t

 3 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_CONTROL

10  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 #else

18  msg.msg_accrights = (caddr_t)&newfd;

19  msg.msg_accrightslen = sizeof(int);

20 #endif

21  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_CONTROL

30  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  } else

38   *recvfd = -1; /* дескриптор не был передан */

39 #else

40  if (msg.msg_accrightslen == sizeof(int))

41   *recvfd = newfd;

42  else

43   *recvfd = -1; /* дескриптор не был передан */

44 #endif

45  return (n);

46 }

8-26
 Эта функция должна работать с обеими версиями функции
recvmsg
: с элементом
msg_control
и с элементом
msg_accrights
. Наш заголовочный файл
config.h
(см. листинг Г.2) определяет константу
HAVE_MSGHDR_MSG_CONTROL
, если поддерживается версия функции
recvmsg
с
msg_control
.

Проверка выравнивания буфера msg_control

10-13
 Буфер
msg_control
должен быть выровнен в соответствии со структурой
msghdr
. Просто выделить в памяти массив типа
char
недостаточно. Здесь мы объявляем объединение, состоящее из структуры
cmsghdr
и символьного массива, что гарантирует необходимое выравнивание массива. Возможно и другое решение — вызвать функцию
malloc
, но это потребует освобождения памяти перед завершением функции.

27-45
 Вызывается функция
recvmsg
. Если возвращаются вспомогательные данные, их формат будет таким, как показано на рис. 14.4. Мы проверяем, верны ли длина, уровень и тип, затем получаем вновь созданный дескриптор и возвращаем его через указатель вызывающего процесса
recvfd
. Макрос
CMSG_DATA
возвращает указатель на элемент
cmsg_data
объекта вспомогательных данных как указатель на элемент типа
unsigned char
. Мы преобразуем его к указателю на элемент типа
int
и получаем целочисленный дескриптор, на который указывает этот указатель.

Перейти на страницу:
Комментариев (0)
название