178: /* Если выполнить разветвление перед вызовом handleRequest и
179: завершить
дочерний процесс после возврата функции, то данный
180: сервер будет работать точно как параллельный tftp-сервер */
181: handleRequest(*addr, from, fromLen, packet);
182: }
183: }
17.7. Ошибки сокетов
Некоторые значения
errno
встречаются только при работе с сокетами. Ниже приведен список специфических ошибок сокетов вместе с краткими их описаниями.
EADDRINUSE
Запрашиваемый адрес уже используется и не может быть переприсвоен.
EADDRNOTAVAIL
Запрашивается несуществующий адрес.
EAFNOSUPPORT
Указано неподдерживаемое семейство адресов.
ECONNABORTED
Соединение прервано программным обеспечением.
ECONNREFUSED
Удаленная машина отклонила попытку соединения.
ECONNRESET
Соединение переустановлено удаленным концом. Это, как правило, указывает на то, что удаленная машина была перезагружена.
EDESTADDRREQ
Выполнена попытка передачи данных через сокет без предоставления адреса назначения. Это может происходить только в дейтаграммных сокетах.
EHOSTDOWN
Удаленный хост не находится в сети.
EHOSTUNREACH
Удаленный хост недоступен.
EISCONN
Для сокета уже установлено соединение.
EMSGSIZE
Данные, передаваемые через сокет, слишком велики для отправления в одном элементарном сообщении.
ENETDOWN
Сетевое соединение прекратилось.
ENETRESET
Сеть была сброшена, что вызвало потерю соединения.
ENETUNREACH
Указанная сеть недоступна.
ENOBUFS
Для обработки запроса доступного пространства буфера недостаточно.
ENOPROTOOPT
Выполнена попытка установить неправильную опцию.
ENOTCONN
До выполнения операции необходимо установить соединение.
ENOTSOCK
Специфическая сокетная операция была направлена на файловый дескриптор, который ссылается не на сокет.
EPFNOSUPPORT
Указано неподдерживаемое семейство протоколов.
EPROTONOSUPPORT
Запрос был сделан для неподдерживаемого протокола.
EPROTOTYPE
Для сокета был указан несоответствующий тип протокола.
ESOCKTNOSUPPORT
Выполнена попытка создания неподдерживаемого типа сокета.
ETIMEDOUT
Время соединения истекло.
17.8. Унаследованные сетевые функции
В данный момент действует множество библиотечных функций, относящихся к работе сетей TCP/IP, которые нельзя применять в новых приложениях. Однако они широко используются в существующих IPv4-программах. В связи с этим они рассматриваются ниже для того, чтобы помочь вам понять и обновить старые коды.
17.8.1. Манипулирование IPv4-адресами
Функции
inet_ntop
и
inet_pton
являются относительно новыми и были введены для того, чтобы один набор функций мог обрабатывать и IPv4-, и IPv6-адреса. До их появления в программах использовались функции
inet_addr
,
inet_aton
и
inet_ntoa
, которые предназначены только для IPv4.
Вспомните, что
struct sockaddr_in
определяется следующим образом
struct sockaddr__in {
short int sin_family; /* AF_INET */
unsigned short int sin_port; /* номер порта */
struct in_addr sin_addr; /* IP-адрес */
}
Член
sin_addr
представляет собой структуру
struct in_addr
; унаследованные функции используют его в качестве параметра [145] . Подразумевается, что данная структура является непрозрачной; программы приложений могут обрабатывать
struct in_addr
исключительно через библиотечные функции. Старой функцией для преобразования IPv4-адреса в десятичную форму с разделительными точками служит
inet_ntoa
.
145
Применение этой структуры делает невозможным расширение данных функций на IPv6 без изменения их интерфейса.
#include <netinet/in.h>
#include <arpa/inet.h>
char * inet_ntoa(struct in_addr address);
Передаваемый адрес преобразуется в строку в десятичном формате с разделительными точками, возвращается указатель на данную строку. Строка сохраняется в статическом буфере библиотеки С и уничтожается при следующем вызове
Существуют две функции, которые предлагают обратное преобразование десятичной строки в двоичный IP-адрес. Более старая из них функция
inet_addr
имеет две проблемы, обе вызванные тем, что она возвращает результат типа
long
. Она не возвращает
struct in_addr
, как предполагается остальными стандартными функциями, поэтому программисты были вынуждены выполнять неуклюжие приведения. К тому же, если переменная типа
long
имела 32 бита, то программы не могли различить возврат числа -1 (что указывает на ошибку, например, неправильный адрес) и двоичного представления адреса 255.255.255.255.
146
Функции, использующие статическую память для сохранения результатов, усложняют построение многопоточных приложений, поскольку в код приложения требуется добавлять блокировки для защиты этих статических буферов.
#include <netinet/in.h>
#include <arpa/inet.h>
unsigned long int inet_addr(const char * ddaddress);
Функция принимает передаваемую строку, которая должна содержать десятичный IP-адрес с разделительными точками, и преобразует ее в двоичный IP-адрес.
Для исправления недостатков
inet_addr
была введена функция
inet_aton
.
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char * ddaddress, struct in_addr * address);
Данная функция ожидает строку, содержащую десятичный IP-адрес, и размещает двоичное представление этого адреса в структуре
struct in_addr
, на которую указывает параметр
address
. В отличие от большинства библиотечных функций
inet_aton
возвращает нуль в случае ошибки и ненулевое значение, если преобразование прошло успешно.
17.8.2. Преобразование имен хостов
Функции
getaddrinfo
,
getnameinfo
, позволяющие легко создавать программы, которые поддерживают и IPv4, и IPv6, были введены именно с этой целью. Исходные функции имен хостов было сложно расширить на IPv6, их интерфейсы требовали, чтобы приложения учитывали множество особенностей версии в структурах, сохраняющих IP-адрес. Новые интерфейсы абстрактны, поэтому поддерживают IPv4 и IPv6 одинаково.
Вместо того чтобы возвращать связный список, как это делает
getaddrinfo
, старые функции имен хостов используют
struct hostent
, которая может содержать все имена хостов и адреса для одного хоста.