случае ошибки возвращается -1, а переменная errno устанавливается следующим образом:
♦ EBADF — неверный дескриптор сокета:
♦ ENOTSOCK — указанный дескриптор является файлом, а не сокетом;
♦ EFAULT — нет доступа к адресу, на который указывает указатель optval
, то есть данный адрес находится за пределами видимости приложения.
Функция getsockopt() возвращает значение параметра. Кроме вышеперечисленных параметров, функция getsockopt() может использовать следующие параметры:
♦ SO_ERROR — возвращает номер ошибки (будет в возвращаемом значении);
♦ SO_TYPE — возвращает тип сокета.
Рассмотрим небольшой пример работы с опциями сокетов. Мы установим размер буфера TCP.
#include 'sock.h'
#include 'stdio.h'
main() {
int sd; /* дескриптор сокета */
int optval; /* значение опции */
int optlen; /* длина optval */
int new_buffsize = 8192; /* новый размер буфера */
/* создаем сокет */
sd = socket(AF_INET, SOCK_STREAM, 0);
/* считывание длины буфера TCP */
optlen = sizeof(optval);
getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen);
printf('Size of send buffer %d
', optval);
getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);
printf('Size of recv buffer %d
', optval);
/* изменяем длину буфера */
setsockopt(sd, SOL_SOCKET, SO_RCVBUF,
&new_buffsize, sizeof(new_buffsize));
setsockopt(sd, SOL_SOCKET, SO_SNDBUF,
&new_buffsize, sizeof(new_buffsize));
/* выводим измененную информацию */
getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen);
printf('New size of send buffer %d
', optval);
getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);
printf('New size of recv buffer %d
', optval);
}
27.3.10. Сигналы и сокеты
С сокетами связаны три сигнала:
♦ SIGIO — сокет готов к вводу/выводу. Сигнал посылается процессу, который связан с сокетом;
♦ SIGURG — сокет получил экспресс-данные (мы их использовать не будем, поэтому особо останавливаться на них нет смысла);
♦ SIGPIPE — запись в сокет больше невозможна. Сигнал посылается процессу, связанному с сокетом. Например, функция write() вызывает сигнал SIGPIPE, если удаленный процесс завершен или связь по сети невозможна.
Пример обработки сигнала SIGPIPE приведен ниже.
Листинг 27.6. Обработка сигнала SIGPIPE
#include 'sock.h'
#include <signal.h>
/* обработчик сигнала SIGPIPE */
sigpipe_handler() {
err_quit('Получен SIGPIPE
');
}
main() {
int sock; /* дескриптор сокета */
/* установка обработчика сигнала SIGPIPE */
signal(SIGPIPE, sigpipe_handler);
/* работа с сокетом */
}
27.3.11. Мультиплексирование
В этой главе мы рассматривали пример программы-сервера, обрабатывающей запросы только от одного клиента. На практике все выглядит намного сложнее: серверу приходится одновременно обрабатывать запросы многих клиентов. Для мультиплексирования запросов клиентов используется системный вызов select(). Этот вызов использует, например, суперсервер xinetd.
Листинг 27.7. Мультиплексирование запросов
#include 'sock.h'
#include <sys/time.h>
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 секунд */