Читаем Linux: Полное руководство полностью

 printf("New size of send buffer %d\n", optval);

 getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);

 printf("New size of recv buffer %d\n", optval);

}

<p>27.3.10. Сигналы и сокеты</p>

С сокетами связаны три сигнала:

♦ SIGIO — сокет готов к вводу/выводу. Сигнал посылается процессу, который связан с сокетом;

♦ SIGURG — сокет получил экспресс-данные (мы их использовать не будем, поэтому особо останавливаться на них нет смысла);

♦ SIGPIPE — запись в сокет больше невозможна. Сигнал посылается процессу, связанному с сокетом. Например, функция write() вызывает сигнал SIGPIPE, если удаленный процесс завершен или связь по сети невозможна.

Пример обработки сигнала SIGPIPE приведен ниже.

Листинг 27.6. Обработка сигнала SIGPIPE

#include "sock.h"

#include

/* обработчик сигнала SIGPIPE */

sigpipe_handler() {

 err_quit("Получен SIGPIPE \n");

}

main() {

 int sock; /* дескриптор сокета */

 /* установка обработчика сигнала SIGPIPE */

 signal(SIGPIPE, sigpipe_handler);

 /* работа с сокетом */

}

<p>27.3.11. Мультиплексирование</p>

В этой главе мы рассматривали пример программы-сервера, обрабатывающей запросы только от одного клиента. На практике все выглядит намного сложнее: серверу приходится одновременно обрабатывать запросы многих клиентов. Для мультиплексирования запросов клиентов используется системный вызов select(). Этот вызов использует, например, суперсервер xinetd.

Листинг 27.7. Мультиплексирование запросов

#include "sock.h"

#include

main() {

 int sock; /* дескриптор исходного сокета */

 int new_sock; /* дескриптор, полученный с помощью accept */

 int retval; /* возвращаемое значение */

 struct sockaddr_in server; /* адрес сокета */

 fd_set readv; /* переменная для select */

 fd_set writev; /* переменная для select */

 struct timeval tout; /* тайм-аут для select */

 /* бесконечный цикл ожидания */

 for (;;) {

  /* процесс ждет операцию ввода-вывода на сокете;

     одновременно можно ждать и другие операции */

  FD_ZERO(&readv);

  FD_ZERO(&writev);

  FD_SET(sock, &readv);

  FD_SET(sock, &writev);

  tout.tv_sec = 10; /* 10 секунд */

  retval = select(sock+1, &readv, &writev, 0, &to);

  /* если select возвращает нулевое значение, значит тайм-аут */

  if (retval == 0) {

   err_ret("timeout");

   continue;

  }

  /* в противном случае, ищем соответствующий дескриптор */

  if ( (FD_ISSET(sock, &readv)) || (FD_ISSET(sock, &writev))) {

   /* прием связи с сокета */

   new_sock = accept(sock, (struct sockaddr *)0, (int *)0);

   /* работа с сокетом new_sock */

   ...

   /* закрытие текущей связи */

   close(new_sock);

  } else {

   err_ret("Это не сокет! Проверьте все дескрипторы\n");

  }

 }

}

Системный вызов select() принимает 5 аргументов:

int select(int fd, fd_set *input, fd_set *output,

 fd_set *error, struct timeval *timeout);

Первый аргумент, fd, — это файловый дескриптор, который может быть сокетом. Следующие три аргумента задают множества файловых дескрипторов для ожидания условий ввода (input), вывода (output) и ошибок (error). Последний аргумент — это тайм-аут.

Множества файловых дескрипторов инициализируются с помощью трех макросов:

FD_ZERO(fd_set);

FD_SET(fd, fd_set);

FD_CLR(fd, fd_set);

Перейти на страницу:

Все книги серии Полное руководство

Похожие книги