Аргумент backlog определяет допустимое количество отложенных соединений (так же, как listen()).

Если аргумент addrlen является ненулевым указателем, то участок памяти, на который он ссылается, будет содержать итоговый размер структуры с адресом сокета, связанного с возвращенным файловым дескриптором. Это значение позволяет выделить буфер подходящего размера, в который будет помещен адрес сокета; позже, если понадобится адрес подключающегося клиента, можно передать его функции accept().

Функция inetBind() создает сокет типа type и привязывает его к универсальному IP-адресу и порту, заданному с помощью аргументов service и type (тип сокета определяет протокол службы — TCP или UDP). Эта функция в основном предназначена для создания и привязки сокетов к определенному адресу в UDP-серверах и их клиентах.

#include "inet_sockets.h"

int inetBind(const char *service, int type, socklen_t *addrlen);

Возвращает файловый дескриптор или -1 при ошибке

Файловый дескриптор нового сокета возвращается в качестве результата выполнения функции.

Функция inetBind(), как и inetListen(), возвращает размер структуры с адресом заданного сокета, используя участок памяти, на который ссылается аргумент addrlen. Это может пригодиться, если нужно выделить буфер, впоследствии передаваемый в вызов recvfrom(), — так можно получить адрес сокета, передающего датаграмму. (Большинство действий, которые нужно выполнить для применения функций inetListen() и inetBind(), совпадают; они реализованы в виде единого вызова под названием inetPassiveSocket().)

Функция inetAddressStr() приводит адрес интернет-сокета к презентационному виду.

#include "inet_sockets.h"

char *inetAddressStr(const struct sockaddr *addr, socklen_t addrlen,

char *addrStr, int addrStrLen);

Возвращает указатель на 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;

}

}

Перейти на страницу:

Похожие книги