Аргумент backlog определяет допустимое количество отложенных соединений (так же, как listen()).
Если аргумент addrlen является ненулевым указателем, то участок памяти, на который он ссылается, будет содержать итоговый размер структуры с адресом сокета, связанного с возвращенным файловым дескриптором. Это значение позволяет выделить буфер подходящего размера, в который будет помещен адрес сокета; позже, если понадобится адрес подключающегося клиента, можно передать его функции accept().
Функция inetBind() создает сокет типа type и привязывает его к универсальному IP-адресу и порту, заданному с помощью аргументов service и type (тип сокета определяет протокол службы — TCP или UDP). Эта функция в основном предназначена для создания и привязки сокетов к определенному адресу в UDP-серверах и их клиентах.
#include "inet_sockets.h"
int inetBind(const char *
Возвращает файловый дескриптор или -1 при ошибке
Файловый дескриптор нового сокета возвращается в качестве результата выполнения функции.
Функция inetBind(), как и inetListen(), возвращает размер структуры с адресом заданного сокета, используя участок памяти, на который ссылается аргумент addrlen. Это может пригодиться, если нужно выделить буфер, впоследствии передаваемый в вызов recvfrom(), — так можно получить адрес сокета, передающего датаграмму. (Большинство действий, которые нужно выполнить для применения функций inetListen() и inetBind(), совпадают; они реализованы в виде единого вызова под названием inetPassiveSocket().)
Функция inetAddressStr() приводит адрес интернет-сокета к презентационному виду.
#include "inet_sockets.h"
char *inetAddressStr(const struct sockaddr *
char *
Возвращает указатель на addrStr (строку, хранящую имена узла и службы)
На основе структуры с адресом сокета, которая передается в аргумент addr и имеет размер addrlen, функция inetAddressStr() возвращает строку с нулевым символом в конце, содержащую соответствующие имя узла и номер порта в следующем формате:
(hostname, port-number)
Эта строка возвращается в буфере, на который указывает аргумент addrStr. Вызывающий процесс должен задать размер данного буфера с помощью addrStrLen. Полученная строка урезается, если ее размер превышает (addrStrLen — 1) байт. Рекомендуемый размер буфера addrStr определен в константе IS_ADDR_STR_LEN; этого значения должно быть достаточно для того, чтобы вместить любые строки, которые можно получить. В качестве результата функция inetAddressStr() возвращает addrStr.
Реализация функций, описанных в данном разделе, представлена в листинге 55.9.
Листинг 55.9. Библиотека для работы с сокетами интернет-домена
sockets/inet_sockets.c
#define _BSD_SOURCE /* Для получения определений NI_MAXHOST и NI_MAXSERV из
#include
#include
#include
#include
#include "inet_sockets.h" /* Объявляет функции, определяемые здесь */
#include "tlpi_hdr.h"
int
inetConnect(const char *host, const char *service, int type)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
hints.ai_family = AF_UNSPEC; /* Поддерживает IPv4 или IPv6 */
hints.ai_socktype = type;
s = getaddrinfo(host, service, &hints, &result);
if (s!= 0) {
errno = ENOSYS;
return -1;
}
/* Перебираем полученный список, пока не найдем структуру с адресом,
с помощью которого можно успешно подключиться к сокету */
for (rp = result; rp!= NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue; /* В случае ошибки пробуем следующий адрес */
if (connect(sfd, rp->ai_addr, rp->ai_addrlen)!= -1)
break; /* Успех */
/* Ошибка соединения: закрываем этот сокет и пробуем следующий адрес */
close(sfd);
}
freeaddrinfo(result);
return (rp == NULL)? — 1: sfd;
}
static int /* Публичные интерфейсы: inetBind() и inetListen() */
inetPassiveSocket(const char *service, int type, socklen_t *addrlen,
Boolean doListen, int backlog)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, optval, s;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
hints.ai_socktype = type;
hints.ai_family = AF_UNSPEC; /* Поддерживает IPv4 или IPv6 */
hints.ai_flags = AI_PASSIVE; /* Используем универсальный IP-адрес */
s = getaddrinfo(NULL, service, &hints, &result);
if (s!= 0)
return -1;
/* Перебираем полученный список, пока не найдем структуру с адресом,
с помощью которого можно успешно создать и привязать сокет */
optval = 1;
for (rp = result; rp!= NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue; /* В случае ошибки пробуем следующий адрес */
if (doListen) {
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval)) == -1) {
close(sfd);
freeaddrinfo(result);
return -1;
}
}