UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
16 if (strlen(temp) >= len) {
17 errno = ENOSPC;
18 return (NULL);
19 }
20 strcpy(strptr, temp);
21 return (strptr);
22 }
23 errno = EAFNOSUPPORT;
24 return (NULL);
25 }
3.8. Функция sock_ntop и связанные с ней функции
Основная проблема, связанная с функцией
inet_ntop
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 *<i>sockaddr</i>, socklen_t <i>addrlen</i>);
<i>Возвращает: непустой указатель, если функция выполнена успешно, NULL в случае ошибки</i>
sockaddr
addrlen
sock_ntop
Формат представления — либо точечно-десятичная форма записи адреса IPv4, либо шестнадцатеричная форма записи адреса IPv6, за которой следует завершающий символ (мы используем точку, как в программе
netstat
INET_ADDRSTRLEN
INET6_ADDRSTRLEN
Обратите внимание, что при статическом хранении результата функция не допускает повторного вхождения (не является повторно входимой) и не может быть использована несколькими программными потоками (не является безопасной в многопоточной среде — 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 <i>sockfd</i>, int <i>family</i>);
<i>Возвращает: 0 в случае успешного выполнения функции, -1 в случае ошибки</i>
int sock_cmp_addr(const struct sockaddr *<i>sockaddr1</i>,
const struct sockaddr *<i>sockaddr2</i>, socklen_t <i>addrlen</i>);
<i>Возвращает: 0, если адреса относятся к одному семейству и совпадают, ненулевое значение в противном случае</i>
int sock_cmp_port(const struct sockaddr *<i>sockaddr1</i>,
const struct sockaddr *<i>sockaddr2</i>, socklen_t <i>addrlen</i>);
<i>Возвращает: 0, если адреса относятся к одному семейству и порты совпадают, ненулевое значение в противном случае</i>
int sock_get_port(const struct sockaddr *<i>sockaddr</i>, socklen_t <i>addrlen</i>);
<i>Возвращает: неотрицательный номер порта для адресов IPv4 или IPv6, иначе -1</i>
char *sock_ntop_host(const struct sockaddr *<i>sockaddr</i>, socklen_t <i>addrlen</i>);
<i>Возвращает: непустой указатель в случае успешного выполнения функции, NULL в случае ошибки</i>
void sock_set_addr(const struct sockaddr *<i>sockaddr</i>,
socklen_t <i>addrlen</i>, void *<i>ptr</i>);
void sock_set_port(const struct sockaddr *<i>sockaddr</i>,
socklen_t <i>addrlen</i>, int <i>port</i>);