Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


gethostbyname(), gethostbyaddr()



Получают IP адрес хоста по имени или наоборот.

Прототип

#include < sys/socket.h>

#include < netdb.h>

struct hostent *gethostbyname(const char *name); // УСТАРЕЛО! struct hostent *gethostbyaddr(const char *addr, int len, int type);

Описание

Эти функции заменены на getaddrinfo()и

getnameinfo()! В частности, gethostbyname()не очень хорошо работает с IPv6.

Эти функции выполняют преобразование имён хостов в IP адреса и обратно. Например, если есть“ www. example. com”, можно использовать gethostbyname()чтобы получить IP адрес и сохранить его в struct in_addr.

И наооборот, если у вас есть struct in_addr или struct in6_addr, можете воспользоваться gethostbyaddr()чтобы получить назад имя хоста. gethostbyaddr()совместима с IPv6, но пользоваться нужно getnameinfo()поновее и поярче.

(Если у вас есть строка с IP адресом в формате цифр-и-точек для которой вы хотите узнать имя хоста, то вам лучше воспользоваться getaddrinfo()с флагом AI_CANONNAME.)

gethostbyname()принимает строку вроде “www.guap.ru” и возвращает struct hostent, которая содержит тонны информации, включая IP адрес. (Другая информация это официальное имя хоста, список псевдонимов, тип адреса и список адресов. Это структура общего назначения и вы увидели как очень просто использовать её в наших особых целях.)

gethostbyaddr()принимает struct in_addr или struct in6_addr и выдаёт соответствующее имя хоста (если оно есть), так что это функция, обратная gethostbyname(). Насчёт параметров, даже хотя addr меет тип char*, в действительности вам надо передавать указатель на struct in_addr. len должна быть sizeof(struct in_addr), и type должен быть AF_INET.

Что это за struct hostent, которую нам возвращают? Она содержит множество полей, содержащих информацию о запрошенном хосте.

char *h_name Настоящее каноническое имя хоста

char **h_aliases Список псевдонимов, к нему можно обращаться, как к массиву, последний элемент содержит NULL

int h_addrtype Тип адреса результата, в нашем случае должен быть AF_INET

int length Длина адресов в байтах (4 для IPv4)

char **h_addr_list Список IP адресов этого хоста. Хоть он и char**, в

действительности это массив переодетых struct in_addr*.

Последний элемент массива равен NULL.

h_addr Псевдоним h_addr_list[0]. Если вам нужен любой старый IP адрес этого хоста (да, у них может быть несколько) используйте это поле.

Возвращаемое значение

Возвращает указатель на получившуюся struct hostent или NULL при ошибке.

Вместо нормальной perror()и всего прилагающегося для выдачи сообщений об ошибке, эти функции пишут результат в переменную h_errno, которую можно распечатать функциями herror()или hstrerror(). Это подобно классической errno, perror(), и strerror().

#include < stdio.h>

#include < errno.h>

#include < netdb.h>

#include < sys/types.h>

#include < sys/socket.h>

#include < netinet/in.h>

#include < arpa/inet.h>

int main(int argc, char *argv[])

{

int i;

struct hostent *he;

struct in_addr **addr_list;

if (argc! = 2) {

fprintf(stderr, " usage: ghbn hostname\n" );

return 1;

}

if ((he = gethostbyname(argv[1])) == NULL) { // получить информацию хоста

herror(" gethostbyname" );

return 2;

}

// распечатать информацию об этом хосте:

printf(" Official name is: %s\n", he-> h_name);

printf(" IP addresses: " );

addr_list = (struct in_addr **)he-> h_addr_list;

for(i = 0; addr_list[i]! = NULL; i++) {

printf(" %s ", inet_ntoa(*addr_list[i]));

}

printf(“\n" );

return 0;

}

// ЭТО ЗАМЕНЕНО

// взамен используйте getnameinfo()!

struct hostent *he; struct in_addr ipv4addr;

struct in6_addr ipv6addr;

inet_pton(AF_INET, " 192.0.2.34", & ipv4addr);

he = gethostbyaddr(& ipv4addr, sizeof ipv4addr, AF_INET); printf(" Host name: %s\n", he-> h_name);

inet_pton(AF_INET6, " 2001: db8: 63b3: 1:: beef", & ipv6addr); he = gethostbyaddr(& ipv6addr, sizeof ipv6addr, AF_INET6);

printf(" Host name: %s\n", he-> h_name);

 

Errno

Содержит код ошибки последнего системного вызова.

Прототип

 

#include < errno.h>

int errno;

Описание

Эта переменная содержит информацию об ошибках для множества системных вызовов. Если при вызове, например, socket()или listen()происходит ошибка, то возвращается -1 и в errno устанавливается код, позволяющий точно определить, что случилось.

В заголовочном файле errno.h перечислены все символические имена ошибок, как EADDRINUSE, EPIPE, ECONNREFUSED и т.д.

В большинстве систем errno определена потокобезопасным способом. (То есть, в действительности она не глобальная переменная, но ведёт себя так, как должна вести себя глобальная переменная в однопотоковой среде.)

Возвращаемое значение

Значение переменной это код последней произошедшей ошибки, но может означать

“успех” если последнее действие завершилось удачно.

Пример

 

s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) {

perror(" socket" ); // или используйте strerror()

}

tryagain:

if (select(n, & readfds, NULL, NULL) == -1) {

// ошибочка вышла!!

// если мы просто прерваны, просто перезапуск вызовом select():

if (errno == EINTR) goto tryagain; // AAAA! goto!!!

// иначе это ошибка посерьёзней:

perror(" select" );

exit(1);

}

Listen()

Предписывает сокету слушать входящие подключения.

Прототип

 

#include < sys/socket.h>

int listen(int s, int backlog);

Описание

Параметр backlog означает резерв - сколько ожидающих соединений можете иметь до того, как ядро начнёт отбрасывать новые. Так что, как только придёт новое соединение, необходимо быстро принять (accept()) его, чтобы не переполнять резерв. Можно установить 10 или около того, и если при высокой нагрузке, ваши клиенты начнут получать “Connection refused” (“Соединение отвергнуто”), следует установить побольше.

Перед вызовом listen()сервер должен вызвать bind()чтобы подключиться к определённому номеру порта. Клиенты будут подключаться к этому порту на IP адресе сервера.

Возвращаемое значение

Возвращает 0 при успехе или -1 в случае ошибки (errno устанавливается соответственно).

Пример

struct addrinfo hints, *res; int sockfd;

// сначала заполняем адресные структуры с помощью getaddrinfo(): memset(& hints, 0, sizeof hints);

hints.ai_family = AF_UNSPEC; // использовать либо IPv4 либо IPv6

hints.ai_socktype = SOCK_STREAM;

hints.ai_flags = AI_PASSIVE; // заполнить мой IP для меня getaddrinfo(NULL, " 3490", & hints, & res);

// создать сокет:

sockfd = socket(res-> ai_family, res-> ai_socktype, res-> ai_protocol);

// связать с портом, переданным getaddrinfo(): bind(sockfd, res-> ai_addr, res-> ai_addrlen); listen(sockfd, 10);

// теперь слушает

// где-то дальше есть цикл accept()

 

Perror(), strerror()

Распечатывают ошибку как читаемую строку

Прототип

.

#include < stdio.h>

#include < string.h> // для strerror()

Void perror(const char *s); char *strerror(int errnum);

Описание

Очень много функций при ошибке возвращают -1 и записывают в errno некоторое число, и было бы удобно, если бы можно было распечатать в понятной форме.

И perror()это делает. Если необходимо добавить описание перед сообщением об ошибке, следует передать указатель на него в параметре s (можно оставить s как NULL и ничего дополнительно не напечатается.)

Эта функция берёт значение errno, вроде ECONNRESET, и печатает его как “Connection reset by peer.”

Функция strerror()подобна perror(), за исключением того, что она возвращает указатель на строку с сообщением об ошибке для заданного параметром errnum значения (обычно переменная передаётся в errno.)

Возвращаемое значение

strerror()возвращает указатель на строку с сообщением об ошибке.

Пример

 

int s;

s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) { // ошибка вышла

// печатает " socket error: " + сообщение об ошибке:

perror(" socket error" );

}

// подобно:

if (listen(s, 10) == -1) {

// это печатает " an error: " + сообщение об ошибке из errno:

printf(" an error: %s\n", strerror(errno));

}

Recv(), recvfrom()

Принимают данные из сокета.

 

Прототип

 

#include < sys/types.h>

#include < sys/socket.h>

ssize_t recv(int s, void *buf, size_t len, int flags); ssize_t recvfrom(int s, void *buf, size_t len, int flags,

struct sockaddr *from, socklen_t *fromlen);

Описание

Как только сокет создан и подключен, можно принимать из него данные вызовами recv()(для TCP SOCK_STREAM сокетов) и recvfrom()(для UDP SOCK_DGRAM сокетов).

Обе функции принимают дескриптор сокета s, указатель на буфер buf, длину буфера в байтах len, и набор флагов flags, определяющих работу функций.

Дополнительно, recvfrom()принимает struct sockaddr* from, указывающую откуда принимать данные и запишет в fromlen размер struct sockaddr. (Можно тоже инициализировать fromlen размером from или struct sockaddr.)

Возвращаемое значение

Возвращает число действительно принятых данных (что может быть меньше затребованного в параметре len), или -1 при ошибке (errno будет установлен соответственно.)

Если удалённая сторона закрыла соединение, то recv()вернёт 0. Это нормальный способ определения того, что удаленная сторона закрыла соединение.

 

Пример

 

/ потоковые сокеты и recv()

struct addrinfo hints, *res; int sockfd;

char buf[512]; int byte_count;

// получить информацию хоста, создать сокет и подключиться memset(& hints, 0, sizeof hints);

hints.ai_family = AF_UNSPEC; // использовать либо IPv4 либо IPv6 hints.ai_socktype = SOCK_STREAM; getaddrinfo(" www.example.com", " 3490", & hints, & res);

sockfd = socket(res-> ai_family, res-> ai_socktype, res-> ai_protocol); connect(sockfd, res-> ai_addr, res-> ai_addrlen);

// Прекрасно! Мы подключены и можем принимать данные! byte_count = recv(sockfd, buf, sizeof buf, 0);

printf(" recv()'d %d bytes of data in buf\n", byte_count);

//дейтаграммные сокеты и recvfrom()

struct addrinfo hints, *res; int sockfd;

int byte_count; socklen_t fromlen;

struct sockaddr_storage addr; char buf[512];

char ipstr[INET6_ADDRSTRLEN];

// получить информацию хоста, создать сокет и подключиться к порту 4950 memset(& hints, 0, sizeof hints);

hints.ai_family = AF_UNSPEC; // использовать либо IPv4 либо IPv6 hints.ai_socktype = SOCK_DGRAM;

hints.ai_flags = AI_PASSIVE; getaddrinfo(NULL, " 4950", & hints, & res);

sockfd = socket(res-> ai_family, res-> ai_socktype, res-> ai_protocol); bind(sockfd, res-> ai_addr, res-> ai_addrlen);

// accept() не нужен, только recvfrom(): fromlen = sizeof addr;

byte_count = recvfrom(sockfd, buf, sizeof buf, 0, & addr, & fromlen);

printf(" recv()'d %d bytes of data in buf\n", byte_count); printf(" from IP address %s\n",

inet_ntop(addr.ss_family,

addr.ss_family == AF_INET?

((struct sockadd_in *)& addr)-> sin_addr:

((struct sockadd_in6 *)& addr)-> sin6_addr,

ipstr, sizeof ipstr);

Select()

Проверяет готовы ли дескрипторы сокетов к чтению - записи.

Прототип

 

#include < sys/select.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,

struct timeval *timeout);

FD_SET(int fd, fd_set *set); FD_CLR(int fd, fd_set *set); FD_ISSET(int

fd, fd_set*set); FD_ZERO(fd_set *set);

Описание

Функция select()предоставляет способ одновременной проверки множества сокетов на предмет ожидания recv(), готовности к передаче данных через send()без блокирования или возникновения исключения.

После того как макросы вроде FD_SET()использованымассива структур можно передать его функции как один из следующих параметров: readfds если хотите знать, готов ли какой-нибудь сокет из массива к recv(), writefds если какой-либо сокет готов к send(), и/или exceptfds если если нужно узнать произошло ли на каком-нибудь исключение в сокете. Любой их этих параметров может быть NULL если этот тип событий неинтересен. После возврата из select()значения в массиве будут изменены, чтобы показать, какие сокеты готовы к чтению - записи и какие имеют исключения.

Первый параметр, n это наивысший номер дескриптора сокета (они просто int) плюс один.

Напоследок, struct timeval *timeout в конце позволяет указать select()как долго проверять эти массивы. Она вернёт управление при истечении таймаута или при возникновении события, смотря что раньше. В struct timeval есть два поля: tv_sec это количество секунд, к которому добавляется tv_usec, количество микросекунд

(1 000 000 микросекунд в секунде.) Вспомогательные макросы делают следующее:

FD_SET(int fd, fd_set *set); FD_CLR(int fd, fd_set *set); FD_ISSET(int fd, fd_set *set); FD_ZERO(fd_set *set);
Добавляет fd в set. Удаляет fd из set. Возвращает true если fd есть в set. Очищает set.

Возвращаемое значение

Возвращает количество дескрипторов с событиями в массиве, 0 если таймаут истёк и -1 при ошибке (errno устанавливается соответственно.) Кроме того, массивы изменяются чтобы показать готовые сокеты.

 

Пример

 

t s1, s2, n; fd_set readfds; struct timeval tv;

char buf1[256], buf2[256];

// полагаем, что здесь оба подключены к серверу

//s1 = socket(...);

//s2 = socket(...);

//connect(s1, ...)...

//connect(s2, …)...

// заранее очищаем массив FD_ZERO(& readfds);

// добавляем наши дескрипторы в массив FD_SET(s1, & readfds);

FD_SET(s2, & readfds);

// поскольку s2 создан вторым, он “больше” и его используем

// в параметре n в select() n = s2 + 1;

// ждём появления данных на каком-либо сокете (таймаут 10.5 секунд) tv.tv_sec = 10;

tv.tv_usec = 500000;

rv = select(n, & readfds, NULL, NULL, & tv);

if (rv == -1) {

perror(" select" ); // в select() произошла ошибка

} else if (rv == 0) {

printf(" Timeout occurred! No data after 10.5 seconds.\n" );

} else {

// на одном или обоих дескрипторах есть данные

if (FD_ISSET(s1, & readfds)) {

recv(s1, buf1, sizeof buf1, 0);

}

if (FD_ISSET(s2, & readfds)) {

recv(s1, buf2, sizeof buf2, 0);

}

}

 

Socket()

Создаёт дескриптор сокета

Прототип

 

include < sys/types.h>

#include < sys/socket.h>

int socket(int domain, int type, int protocol);

Описание

Возвращает дескриптор сокета, который можно использовать. Обычно это первый шаг в процессе написания программ с сокетами и результат можно использовать в последующих вызовах listen(), bind(), accept()или множества других функций.

Обычно значения параметров получается из вызова getaddrinfo(), как в примере ниже, но можно их заполнять и вручную.

domain определяет тип нужного вам сокета. Их может быть

множество, но поскольку это руководство по сокетам tcp/ip, он будет PF_INET

для IPv4 и PF_INET6 для IPv6.

type Хотя параметр type может принимать множество значений, его следует установить в SOCK_STREAM для надёжных TCP сокетов (send(), recv()) либо SOCK_DGRAM для ненадёжных быстрых UDP сокетов (sendto(), recvfrom().)

protocol Параметр protocol указывает какой протокол использовать для этого типа сокетов, например, SOCK_STREAM использует TCP. Если будет использоваться SOCK_STREAM или SOCK_DGRAM, можно просто установить protocol в 0, и он автоматически использует правильный протокол. Иначе можно использовать getprotobyname()для выбора номера нужного протокола.

Возвращаемое значение

Дескриптор нового сокета для последующих вызовов или -1 при ошибке (и errno

будет установлен соответственно.)

Пример

 

sruct addrinfo hints, *res; int sockfd;

// сначала заполняем адресные структуры с помощью getaddrinfo(): memset(& hints, 0, sizeof hints);

hints.ai_family = AF_UNSPEC; // AF_INET, AF_INET6, или AF_UNSPEC

hints.ai_socktype = SOCK_STREAM; // SOCK_STREAM или SOCK_DGRAM getaddrinfo(" www.example.com", " 3490", & hints, & res);

// создаём сокет с помощью информации, которую наскребла getaddrinfo(): sockfd = socket(res-> ai_family, res-> ai_socktype, res-> ai_protocol);

 

13. setsockopt(), getsockopt()

Устанавливает для сокета различные опции.

Прототип

#include < sys/types.h>

#include < sys/socket.h>

int getsockopt(int s, int level, int optname, void *optval,

socklen_t *optlen);

int setsockopt(int s, int level, int optname, const void *optval,

socklen_t optlen);

Описание

Эти функции получают и устанавливают определённые опции сокета.

Параметры это s это сокет, level должен быть установлен в SOL_SOCKET. Затем, в optname установается имя которое связывает сокет с символическим именем устройства вроде eth0 вместо использования bind()для привязки к IP адресу. Позволяет другим сокетам связываться (bind()) с этим портом, несмотря на то, что уже существует активный сокет, слушающий этот порт. Это позволяет обойти сообщения “Address already in use”, когда вы пытаетесь перезапустить ваш сервер после обрушения. Позволяет UDP дейтаграммным (SOCK_DGRAM) сокетам посылать пакеты по широковещательным адресам и принимать и с них. Насчёт параметра optval, обычно это указатель на int, показывающую значение запроса.

 

Последний параметр, optlen, заполняется getsockopt()если необходимо указать его для setsockopt(), возможно он будет sizeof(int).

Возвращаемое значение

Возвращает 0 при успехе или -1 в случае ошибки (errno устанавливается соответственно).

Пример

 

int optval; int optlen;

char *optval2;

// установить SO_REUSEADDR на сокете в ИСТИННО (1): optval = 1;

setsockopt(s1, SOL_SOCKET, SO_REUSEADDR, & optval, sizeof optval);

// связать сокет с именем устройства (может не работать на некоторых системах): optval2 = " eth1"; // 4 байта длины, итого 4, ниже:

setsockopt(s2, SOL_SOCKET, SO_BINDTODEVICE, optval2, 4);

// посмотреть установлен ли флаг SO_BROADCAST: getsockopt(s3, SOL_SOCKET, SO_BROADCAST, & optval, & optlen); if (optval! = 0) {

print(" SO_BROADCAST enabled on s3! \n" );

}

Send(), sendto()

Посылают данные через сокет.

Прототип

#include < sys/types.h>

#include < sys/socket.h>

ssize_t send(int s, const void *buf, size_t len, int flags); ssize_t sendto(int s, const void *buf, size_t len,

int flags, const struct sockaddr *to, socklen_t tolen);

Описание

Эти функции посылают данные в сокет. В общем случае send()используется для TCP SOCK_STREAM п о д к л ю ч ё н н ы х с о к е т о в, а sendto()д л я U D P SOCK_DGRAM неподключённых дейтаграммных сокетов. Каждый раз посылая пакет по неподключённому сокету вы должны указывать место назначения, поэтому последние параметры sendto()задают куда пакет направляется.

В обоих, send()и sendto(), параметр s это сокет, buf указатель на данные, которые необходимо послать, len число посылаемых байт и flags позволяет определить дополнительную информацию как посылать данные. Установите flags в ноль, если хотите иметь “нормальные” данные. Ниже приведены несколько наиболее часто используемых флагов:

MSG_OOB Посылает “out of band” данные. TCP поддерживает этот способ

Сообщить принимающей стороне, что у этих данных приоритет выше, чем у нормальных. Приёмник получит сигнал SIGURG и примет эти данные без предварительной выборки нормальных данных из очереди.

MSG_DONTROUTE Не посылать эти данные через маршрутизатор, они местные.

MSG_DONTWAIT Если send()должна блокироваться из-за загруженности внешнего трафика, она вернёт EAGAIN. Это вроде “Разрешить не блокирование для этой посылки”

MSG_NOSIGNAL send()на удалённый хост, который больше не принимает (recv()) данные, обычно возбуждает сигнал SIGPIPE. Этот флаг предотвращает возбуждение такого сигнала.

Возвращаемое значение

Возвращает число действительно посланных байт или -1 при ошибке (errno устанавливается соответственно.) Заметьте, что это число может быть меньше затребованного. Вспомогательная функция в разделе по send()поможет обойти это.

Также, если сокет был закрыт на противной стороне, процесс, вызвавший send(), получит сигнал SIGPIPE. (Если только send()не был вызван с флагом MSG_NOSIGNAL.)

Пример

 

int spatula_count = 3490;

char *secret_message = " The Cheese is in The Toaster”;

int stream_socket, dgram_socket; struct sockaddr_in dest;

int temp;

// сначала с потоковым сокетом TCP:

// полагаем, что сокеты созданы и подключены

//stream_socket = socket(...

//connect(stream_socket, …

// преобразовать в порядок байтов сети temp = htonl(spatula_count);

// послать данные нормально: send(stream_socket, & temp, sizeof temp, 0);

// послать секретное out of band сообщение:

send(stream_socket, secret_message, strlen(secret_message)+1, MSG_OOB);

 

// теперь с дейтаграммным сокетом UDP:

//getaddrinfo(...

//dest =... // полагаем, что " dest" содержит адрес назначения

//dgram_socket = socket(…

// послать секретное послание нормально:

sendto(dgram_socket, secret_message, strlen(secret_message)+1, 0,

(struct sockaddr*)& dest, sizeof dest);

 

 

14. shutdown()

Останавливает обмен по сокету.

Прототип

 

#include < sys/socket.h>

int shutdown(int s, int how);

Описание

close()) закрывает обе стороны, для чтения и для записи, а дескриптор освобождается. Если необходимо закрыть только одну или другую сторону, следует использовать shutdown().

Параметр s это сокет с которым вы работаете, а что с ним делать определяет параметр how. Это может быть SHUT_RD для предотвращения дальнейших recv(), SHUT_WR для запрещения дальнейших send(), или SHUT_RDWR для обоих.

shutdown()не освобождает дескриптор сокета и в итоге прийдется вызвать close()чтобы закрыть его полностью.

Этот системный вызов используется редко.

Возвращаемое значение

Возвращает 0 при успехе или -1 в случае ошибки (errno устанавливается соответственно).

Пример

 

nt s = socket(PF_INET, SOCK_STREAM, 0);

// …посылаем и обрабатываем здесь…

// и когда всё сделано запрещаем дальнейшие посылки: shutdown(s,

SHUT_WR);

 

 

15. struct sockaddr

Структуры для обработки интернет адресов.

Прототип

nclude < netinet/in.h>

// Все указатели на адресные структуры сокетов часто приводятся

// к этому типу перед их использованием в различных функциях и вызовах:

struct sockaddr {

unsigned short sa_family; // семейство адресов, AF_xxx char sa_data[14]; // 14 байт адреса протокола

};

// IPv4 AF_INET сокеты: struct sockaddr_in {

short sin_family; // например, AF_INET, AF_INET6

unsigned short sin_port; // например, htons(3490)

struct in_addr sin_addr; // смотри struct in_addr, ниже

char sin_zero[8] // обнулите, если хочется

};

struct in_addr {

unsigned long s_addr; // заполнить с помощью inet_pton()

};

// IPv6 AF_INET6 сокеты: struct sockaddr_in6 {

u_int16_t sin6_family; // семейство адресов, AF_INET6 u_int16_t sin6_port; // номер порта, Порядок Байтов Сети u_int32_t sin6_flowinfo; // IPv6 flow information

struct in6_addr sin6_addr; // IPv6 адрес u_int32_t sin6_scope_id; // Scope ID

};

struct in6_addr {

unsigned char s6_addr[16]; // заполнить с помощью inet_pton()

};

// Общая структура хранения адреса сокета достаточно велика для хранения

// данных struct sockaddr_in или struct sockaddr_in6:

struct sockaddr_storage {

sa_family_t ss_family; // семейство адресов

// всё это расширение зависит от реализации, проигнорируйте:

char ss_pad1[_SS_PAD1SIZE];

int64_t ss_align;

char ss_pad2[_SS_PAD2SIZE];

};

Описание

Это базовые структуры для всех системных вызовов и функций, работающих с интернет адресами. Для заполнения этих структур часто используется getaddinfo()а затем, по мере надобности читать их.

В памяти struct sockaddr_in и struct sockaddr_in6 начинаются с одинаковой struct sockaddr, и можно приводить один тип к другому без какого- либо ущерба.

Структура struct sockaddr_in используется с IPv4 адресами (вроде “192.0.2.10”).

Она содержит семейство адресов (AF_INET), порт в sin_port и IPv4 адрес в sin_addr.

Кроме того в struct sockaddr_in есть поле sin_zero , которое должно содержать нули. Это можно сделать с помощью функцией memset().

В struct in_addr чаще всего используется только поле s_addr, поскольку многие системы реализуют только его. struct sockadd_in6 очень похожа на struct in6_addr, но используется для IPv6. struct sockaddr_storage передаётся в accept()или recvfrom()когда необходимо написать код, не зависящий от версии IP, и неизвестно каким будет новый адрес - IPv4 или IPv6. Структура struct sockaddr_storage достаточно велика, чтобы содержать оба типа, в отличие от оригинальной маленькой struct sockaddr.

 

// IPv4:

struct sockaddr_in ip4addr; int s;

ip4addr.sin_family = AF_INET; ip4addr.sin_port = htons(3490);

inet_pton(AF_INET, " 10.0.0.1", & ip4addr.sin_addr); s = socket(PF_INET, SOCK_STREAM, 0);

bind(s, (struct sockaddr*)& ip4addr, sizeof ip4addr);

// IPv6:

struct sockaddr_in6 ip6addr; int s;

ip6addr.sin6_family = AF_INET6; ip6addr.sin6_port = htons(4950);

inet_pton(AF_INET6, " 2001: db8: 8714: 3a90:: 12", & ip6addr.sin6_addr); s = socket(PF_INET6, SOCK_STREAM, 0);

bind(s, (struct sockaddr*)& ip6addr, sizeof ip6addr);


Поделиться:



Последнее изменение этой страницы: 2017-04-12; Просмотров: 1138; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.157 с.)
Главная | Случайная страница | Обратная связь