Чтение онлайн

на главную - закладки

Жанры

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

30 *addrlenp = res->ai_addrlen; /* возвращает размер адреса протокола */

31 freeaddrinfo(ressave);

32 return (listenfd);

33 }

Вызов функции getaddrinfo

8-15
Мы инициализируем структуру
addrinfo
с учетом следующих рекомендаций (элементов структуры
hints
):
AI_PASSIVE
, поскольку это функция для сервера,
AF_UNSPEC
для семейства адресов и
SOCK_STREAM
.
Вспомните табл. 11.3: если имя узла не задано (что вполне нормально для сервера, который хочет связать с дескриптором универсальный адрес), то наличие значений
AI_PASSIVE
и
AF_UNSPEC
вызовет возвращение двух структур адреса сокета: первой для IPv6 и второй для IPv4 (в предположении, что это узел с двойным стеком).

Создание сокета и связывание с адресом

16-24
Вызываются функции
socket
и
bind
. Если любой из вызовов окажется неудачным, мы просто игнорируем данную структуру
addrinfo
и переходим к следующей. Как было сказано в разделе 7.5, для сервера TCP мы всегда устанавливаем параметр сокета
SO_REUSEADDR
.

Проверка на наличие ошибки

25-26
Если все вызовы функций
socket
и
bind
окажутся неудачными, мы сообщаем об ошибке и завершаем выполнение. Как и в случае с нашей функцией
tcp_connect
из предыдущего раздела, мы не пытаемся возвратить ошибку из этой функции.

27
Сокет превращается в прослушиваемый сокет с помощью функции
listen
.

Возвращение размера структуры адреса

28-31
Если аргумент
addrlenp
является непустым указателем, мы возвращаем размер адресов протокола через этот указатель. Это позволяет вызывающему процессу выделять память для структуры адреса сокета, чтобы получить адрес протокола клиента из функции accept (см. также упражнение 11.7).

Пример: сервер времени и даты

В листинге 11.7 показан наш сервер времени и даты из листинга 4.2, переписанный с использованием функции

tcp_listen
.

Листинг 11.7. Сервер времени и даты, переписанный с использованием функции tcp_listen

//names/daytimetcpsrv1.c

1 #include "unp.h"

2 #include <time.h>

3 int

4 main(int argc, char **argv)

5 {

6 int listenfd, connfd;

7 socklen_t addrlen, len;

8 char = buff[MAXLINE];

9 time_t ticks;

10 struct sockaddr_storage cliaddr;

11 if (argc != 2)

12 err_quit("usage: daytimetcpsrv1 <service or port#>");

13 listenfd = Tcp_listen(NULL, argv[1], &addrlen);

14 for (;;) {

15 len = sizeof(cliaddr);

16 connfd = Accept(listenfd, (SA*)&cliaddr, &len);

17 printf("connection from %s\n", Sock_ntop((SA*)&cliaddr, len));

18 ticks = time(NULL);

19 snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));

20 Write(connfd, buff, strlen(buff));

21 Close(connfd);

22 }

23 }

Ввод
имени службы или номера порта в качестве аргумента командной строки

11-12
Нам нужно использовать аргумент командной строки, чтобы задать либо имя службы, либо номер порта. Это упрощает проверку нашего сервера, поскольку связывание с портом 13 для сервера времени и даты требует прав привилегированного пользователя.

Создание прослушиваемого сокета

13
Функция
tcp_listen
создает прослушиваемый сокет. В качестве третьего аргумента мы передаем нулевой указатель, потому что нам безразличен размер структуры адреса, используемого данным семейством: мы будем работать со структурой
sockaddr_storage
.

Цикл сервера

14-22
Функция
accept
ждет соединения с клиентом. Мы выводим адрес клиента, вызывая функцию
sock_ntop
. В случае IPv4 или IPv6 эта функция выводит IP-адрес и номер порта. Мы могли бы использовать функцию
getnameinfo
(описанную в разделе 11.17), чтобы попытаться получить имя узла клиента, но это подразумевает запрос PTR в DNS, что может занять некоторое время, особенно если запрос PTR окажется неудачным. В разделе 14.8 [112] упоминается, что на занятом веб-сервере почти у 25% всех клиентов, соединяющихся с этим сервером, в DNS нет записей типа PTR. Поскольку мы не хотим, чтобы наш сервер (особенно последовательный сервер) в течение нескольких секунд ждал запрос PTR, мы просто выводим IP-адрес и порт.

Пример: сервер времени и даты с указанием протокола

В листинге 11.7 есть небольшая проблема: первый аргумент функции

tcp_listen
— пустой указатель, объединенный с семейством адресов
AF_UNSPEC
, который задает функция
tcp_listen
, — может заставить функцию
getaddrinfo
возвратить структуру адреса сокета с семейством адресов, отличным от желаемого. Например, первой на узле с двойным стеком будет возвращена структура адреса сокета для IPv6 (см. табл. 11.3), но, возможно, нам требуется, чтобы наш сервер обрабатывал только IPv4.

У клиентов такой проблемы нет, поскольку клиент должен всегда задавать либо IP-адрес, либо имя узла. Клиентские приложения обычно позволяют пользователю вводить этот параметр как аргумент командной строки. Это дает нам возможность задавать имя узла, связанное с определенным типом IP-адреса (вспомните наши имена узлов -4 и -6 в разделе 11.2), или же задавать либо строку в точечно-десятичной записи (для IPv4), либо шестнадцатеричную строку (для IPv6).

И для серверов существует простая методика, позволяющая нам указать, какой именно протокол следует использовать — IPv4 или IPv6. Для этого нужно позволить пользователю ввести либо IP-адрес, либо имя узла в качестве аргумента командной строки и передать его функции

getaddrinfo
. В случае IP-адреса строка точечно-десятичной записи IPv4 отличается от шестнадцатеричной строки IPv6. Следующие вызовы функции
inet_pton
оказываются либо успешными либо нет, как это показано в данном случае:

Поделиться:
Популярные книги

Не грози Дубровскому! Том VIII

Панарин Антон
8. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не грози Дубровскому! Том VIII

Para bellum

Ланцов Михаил Алексеевич
4. Фрунзе
Фантастика:
попаданцы
альтернативная история
6.60
рейтинг книги
Para bellum

Архонт

Прокофьев Роман Юрьевич
5. Стеллар
Фантастика:
боевая фантастика
рпг
7.80
рейтинг книги
Архонт

Сильнейший ученик. Том 2

Ткачев Андрей Юрьевич
2. Пробуждение крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Сильнейший ученик. Том 2

Измена. Ребёнок от бывшего мужа

Стар Дана
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Ребёнок от бывшего мужа

Real-Rpg. Город гоблинов

Жгулёв Пётр Николаевич
1. Real-Rpg
Фантастика:
фэнтези
7.81
рейтинг книги
Real-Rpg. Город гоблинов

Хозяйка Междуречья

Алеева Елена
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Хозяйка Междуречья

Крестоносец

Ланцов Михаил Алексеевич
7. Помещик
Фантастика:
героическая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Крестоносец

Эйгор. В потёмках

Кронос Александр
1. Эйгор
Фантастика:
боевая фантастика
7.00
рейтинг книги
Эйгор. В потёмках

Идеальный мир для Лекаря 3

Сапфир Олег
3. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 3

Кодекс Крови. Книга III

Борзых М.
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга III

Вернуть невесту. Ловушка для попаданки 2

Ардова Алиса
2. Вернуть невесту
Любовные романы:
любовно-фантастические романы
7.88
рейтинг книги
Вернуть невесту. Ловушка для попаданки 2

Черный Маг Императора 7 (CИ)

Герда Александр
7. Черный маг императора
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Черный Маг Императора 7 (CИ)

Удобная жена

Волкова Виктория Борисовна
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Удобная жена