Книга: UNIX: разработка сетевых приложений
3.8. Функция sock_ntop и связанные с ней функции
3.8. Функция sock_ntop и связанные с ней функции
Основная проблема, связанная с функцией inet_ntop
, состоит в том, что вызывающий процесс должен передать ей указатель на двоичный адрес. Этот адрес обычно содержится в структуре адреса сокета, поэтому вызывающему процессу необходимо знать формат структуры и семейство адресов. Следовательно, чтобы использовать эту функцию, для IPv4 нужно написать код следующего вида:
struct sockaddr_in addr;
inet_ntop(AF_INET, &addr.sin_addr, str, sizeof(str));
или для IPv6 такого вида:
struct sockaddr_in6 addr6:
inet_ntop(AF_INET6, &addr6.sin6_addr, str, sizeof(str));
Как видите, код становится зависящим от протокола.
Чтобы решить эту проблему, напишем собственную функцию и назовем ее sock_ntop
. Она получает указатель на структуру адреса сокета, исследует эту структуру и вызывает соответствующую функцию для того, чтобы возвратить формат представления адреса.
#include "unp.h"
указывает на структуру адреса сокета, длина которой равна значению
char *sock_ntop(const struct sockaddr *sockaddr, socklen_t addrlen);
Возвращает: непустой указатель, если функция выполнена успешно, NULL в случае ошибки
sockaddraddrlen
. Функция sock_ntop
использует свой собственный статический буфер для хранения результата и возвращает указатель на этот буфер.
Формат представления — либо точечно-десятичная форма записи адреса IPv4, либо шестнадцатеричная форма записи адреса IPv6, за которой следует завершающий символ (мы используем точку, как в программе netstat
), затем десятичный номер порта, а затем завершающий нуль. Следовательно, размер буфера должен быть равен как минимум INET_ADDRSTRLEN
плюс 6 байт для IPv4 (16 + 6 - 22) либо INET6_ADDRSTRLEN
плюс 6 байт для IPv6 (46 + 6 - 52).
ПРИМЕЧАНИЕ
Обратите внимание, что при статическом хранении результата функция не допускает повторного вхождения (не является повторно входимой) и не может быть использована несколькими программными потоками (не является безопасной в многопоточной среде — thread-safe). Более подробно мы поговорим об этом в разделе 11.18. Мы допустили такое решение для этой функции, чтобы ее было легче вызывать из простых программ, приведенных в книге.
В листинге 3.8 представлена часть исходного кода, обрабатывающая семейство AF_INET
.
Листинг 3.8. Наша функция sock_ntop
//lib/sock_ntop.c
5 char *
6 sock_ntop(const struct sockaddr *sa, socklen_t salen)
7 {
8 char portstr[7];
9 static char str[128]; /* макс. длина для доменного сокета Unix */
10 switch (sa->sa_family) {
11 case AF_INET: {
12 struct sockaddr_in *sin = (struct sockaddr_in*)sa;
13 if (inet_ntop(AF_INET, &sin->sin_addr. str, sizeof(str)) == NULL)
14 return (NULL);
15 if (ntohs(sin->sin_port) != 0) {
16 snprintf(portstr, sizeof(portstr), ntohs(sin->sin_port));
17 strcat(str, portstr);
18 }
19 return (str);
20 }
Для работы со структурами адресов сокетов мы определяем еще несколько функций, которые упростят переносимость нашего кода между IPv4 и IPv6.
#include "unp.h"
int sock_bind_wild(int sockfd, int family);
Возвращает: 0 в случае успешного выполнения функции, -1 в случае ошибки
int sock_cmp_addr(const struct sockaddr *sockaddr1,
const struct sockaddr *sockaddr2, socklen_t addrlen);
Возвращает: 0, если адреса относятся к одному семейству и совпадают, ненулевое значение в противном случае
int sock_cmp_port(const struct sockaddr *sockaddr1,
const struct sockaddr *sockaddr2, socklen_t addrlen);
Возвращает: 0, если адреса относятся к одному семейству и порты совпадают, ненулевое значение в противном случае
int sock_get_port(const struct sockaddr *sockaddr, socklen_t addrlen);
Возвращает: неотрицательный номер порта для адресов IPv4 или IPv6, иначе -1
char *sock_ntop_host(const struct sockaddr *sockaddr, socklen_t addrlen);
Возвращает: непустой указатель в случае успешного выполнения функции, NULL в случае ошибки
void sock_set_addr(const struct sockaddr *sockaddr,
socklen_t addrlen, void *ptr);
void sock_set_port(const struct sockaddr *sockaddr,
socklen_t addrlen, int port);
void sock_set_wild(struct sockaddr *sockaddr, socklen_t addrlen);
Функция sock_bind_wild
связывает универсальный адрес и динамически назначаемый порт с сокетом. Функция sock_cmp_addr
сравнивает адресные части двух структур адреса сокета, а функция sock_cmp_port
сравнивает номера их портов. Функция sock_get_port
возвращает только номер порта, а функция sock_ntop_host
преобразует к формату представления только ту часть структуры адреса сокета, которая относится к узлу (все, кроме порта, то есть IP-адрес узла). Функция sock_set_addr
присваивает адресной части структуры значение, указанное аргументом ptr
, а функция sock_set_port
задает в структуре адреса сокета только номер порта. Функция sock_set_wild
задает адресную часть структуры через символы подстановки. Как обычно, мы предоставляем для всех этих функций функции- обертки, которые возвращают значение, отличное от типа void, и в наших программах обычно вызываем именно обертки. Мы не приводим в данной книге исходный код для этих функций, так как он свободно доступен (см. предисловие).
- 3.1. Введение
- 3.2. Структуры адреса сокетов
- 3.3. Аргументы типа «значение-результат»
- 3.4. Функции определения порядка байтов
- 3.5. Функции управления байтами
- 3.6. Функции inet_aton, inet_addr и inet_ntoa
- 3.7. Функции inet_pton и inet_ntop
- 3.8. Функция sock_ntop и связанные с ней функции
- 3.9. Функции readn, writen и readline
- 3.10. Резюме
- Упражнения
- 2.1.3. Функция getopt_long()
- Пять умнейших стерв – это много
- Аргументы функции в Python
- Группировка по встроенным функциям и UDF
- Конструирование нейронных сетей
- 3. Функции
- Новые функции API для работы с Blob и массивами
- Дальнейшее развитие языка SQL
- 19.1.1. Функция jQuery()
- Функция strcmp( )
- 1.4 Структуры данных, связанные с драйверами устройств Windows
- ЭМУЛЯЦИЯ ИСКУССТВЕННЫХ НЕЙРОННЫХ СЕТЕЙ