Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Опрос данных о сети

Читайте также:
  1. I. Революционное народничество 1870-х гг. и современность (Российское народничество и народовольцы: к вопросу об исторической памяти российского народа).
  2. II. МЕТОДИКА ОБРАБОТКИ ДАННЫХ СЕЙСМОКАРОТАЖА
  3. II.1 Использование мастера запросов для создания простых запросов с группированием данных
  4. II.2 Создание простых запросов с группированием данных в режиме конструктора
  5. III. Создание таблицы БД путем импорта данных из таблицы MS Excel
  6. IV. ПОРЯДОК ОБРАБОТКИ ЭКСПЕРИМЕНТАЛЬНЫХ ДАННЫХ
  7. IV. Работа с интервьюерами и проведение опроса

Основные понятия и объекты

Стандарт POSIX-2001 определяет сеть как совокупность взаимосвязанных хостов. Тем самым предполагается, что сетевая инфраструктура остается скрытой от приложений, которым предоставляются высокоуровневые средства взаимодействия в распределенной среде.

Под сетевым адресом понимается видимый в пределах сети идентификатор, используемый для обозначения оконечных точек сети. Адреса есть у определенных оконечных точек хостов, могут они быть и у хостов в целом.

Данные о хостах как узлах сети хранятся в сетевой базе, допускающей и последовательный, и случайный доступ с возможностью поиска по именам и адресам хостов.

Процесс присвоения сетевого адреса оконечной точке называется связыванием, или привязкой, а обратное действие - освобождением, или отменой привязки.

Обычно оконечной точкой служит аппаратный сетевой интерфейс, посредством которого данные передаются и принимаются, однако с таким интерфейсом, как шлейфовый (loopback), никакой аппаратуры не ассоциировано.

Поддерживается база данных маршрутизации, используемая при выборе сетевого интерфейса для передачи порции данных (сетевого пакета).

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

Последовательности октетов - неудобный объект обработки на хостах, где предпочтительнее аппаратно поддерживаемые типы, в особенности целочисленные. Значения этих типов обычно хранятся с другим порядком байт, называемым хостовым, поэтому вполне возможно, что старшего бита не окажется в первом байте и вообще будет использоваться некое неочевидное распределение бит по байтам.

Для преобразования значений типов uint16_t и uint32_t из хостового порядка байт в сетевой служат функции htons() и htonl(); функции ntohs() и ntohl() осуществляют обратную операцию.

При взаимодействии процессов оконечными точками служат сокеты, они трактуются стандартом POSIX-2001 как отдельный тип файлов.

Под адресом сокета как (удаленной) оконечной точки понимается структура, включающая идентификатор адресного семейства и адресную информацию, специфичную для данного семейства. Последняя может состоять из нескольких компонентов, в том числе сетевого адреса хоста и идентификатора конкретной оконечной точки.

Основные описания, относящиеся к сокетам, сосредоточены в заголовочном файле <sys/socket.h>. Фигурирует в нем и упомянутая выше структура sockaddr для адреса сокета, которая должна содержать по крайней мере следующие поля.

sa_family_t sa_family; /* Адресное семейство */char sa_data []; /* Адрес сокета (данные переменной длины) */

Адресное семейство соответствует конкретной среде взаимодействия. Стандарт POSIX-2001 определяет три таких семейства.

AF_UNIX

Адресное семейство UNIX поддерживает межпроцессное взаимодействие в пределах одной системы. Формально это можно считать вырожденным случаем сетевого взаимодействия. Описания, специфичные для данного семейства, содержатся в заголовочном файле <sys/un.h>.

AF_INET

Адресное семейство, поддерживающее взаимодействие по протоколам IPv4. Специфичные для него описания располагаются в заголовочном файле <netinet/in.h>.

AF_INET6

Взаимодействие по протоколам IPv6 (необязательная возможность). За счет поддержки адресов IPv6, отображенных на IPv4, обеспечивается совместимость с приложениями, использующими IPv4. Применяемые эти адресным семейством описания распределены по заголовочным файлам <netinet/in.h>, <arpa/inet.h> и <netdb.h>.

В пределах каждого адресного семейства могут существовать сокеты нескольких типов. В стандарте POSIX-2001 их четыре.

SOCK_STREAM

Сокеты данного типа поддерживают надежные, упорядоченные, полнодуплексные потоки октетов в режиме с установлением соединения.

SOCK_SEQPACKET

Аналог SOCK_STREAM с дополнительным сохранением границ между записями.

SOCK_DGRAM

Передача данных в виде датаграмм в режиме без установления соединения.

SOCK_RAW

(Необязательная возможность). Аналог SOCK_DGRAM с дополнительной возможностью доступа к протокольным заголовкам и другой информации нижнего уровня. Создавать сокеты этого типа могут лишь процессы с соответствующими привилегиями.

Для каждого адресного семейства каждый тип сокета может поддерживаться одним или несколькими протоколами. В частности, в адресном семействе AF_INET для сокетов типа SOCK_STREAM подразумеваемым является протокол с именем IPPROTO_TCP, а для типа SOCK_DGRAM - IPPROTO_UDP; посредством "прозрачных" сокетов (SOCK_RAW) можно воспользоваться протоколом ICMP, задав имя IPPROTO_ICMP, и т.д.

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

Для приема поступивших в сокет данных можно воспользоваться универсальной функцией низкоуровневого ввода/вывода read() или специализированным семейством функций recv*(), а для передачи - функцией write() или семейством send*(). Кроме того, функции select() и/или poll() помогут проверить наличие данных для приема или возможность отправки очередной порции данных.

Обращение к функции shutdown() завершает взаимодействие между партнерами.

Опрос данных о сети

Данные о хостах как узлах сети хранятся в сетевой базе, последовательный доступ к которой обслуживается функциями sethostent(), gethostent() и endhostent() (см. пример 11.1).

#include <netdb.h>void sethostent (int stayopen);struct hostent *gethostent (void);void endhostent (void);

Листинг 11.1. Описание функций последовательного доступа к сетевой базе данных о хостах - узлах сети.

Функция sethostent() устанавливает соединение с базой, остающееся открытым после вызова gethostent(), если значение аргумента stayopen отлично от нуля. Функция gethostent() последовательно читает элементы базы, возвращая результат в структуре типа hostent, содержащей по крайней мере следующие поля.

char *h_name; /* Официальное имя хоста */char **h_aliases; /* Массив указателей на альтернативные *//* имена хоста, завершаемый пустым *//* указателем */int h_addrtype; /* Тип адреса хоста */int h_length; /* Длина в байтах адреса данного типа */char **h_addr_list; /* Массив указателей на сетевые адреса *//* хоста, завершаемый пустым указателем */

Функция endhostent() закрывает соединение с базой.

В пример 11.2 показана программа, осуществляющая последовательный просмотр сетевой базы данных о хостах - узлах сети, а в пример 11.3 приведен фрагмент ее возможной выдачи.

#include <stdio.h>#include <netdb.h> int main (void) { struct hostent *pht; char *pct; int i, j; sethostent (1); while ((pht = gethostent ())!= NULL) { printf ("Официальное имя хоста: %s\n", pht->h_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->h_aliases [i])!= NULL; i++) { printf (" %s\n", pct); } printf ("Тип адреса хоста: %d\n", pht->h_addrtype); printf ("Длина адреса хоста: %d\n", pht->h_length); printf ("Сетевые адреса хоста:\n"); for (i = 0; (pct = pht->h_addr_list [i])!= NULL; i++) { for (j = 0; j < pht->h_length; j++) { printf (" %d", (unsigned char) pct [j]); } printf ("\n"); } } endhostent (); return 0;}

Листинг 11.2. Пример программы, осуществляющей последовательный доступ к сетевой базе данных о хостах - узлах сети.

Официальное имя хоста: localhostАльтернативные имена:Тип адреса хоста: 2Длина адреса хоста: 4Сетевые адреса хоста:127 0 0 1...Официальное имя хоста: t01Альтернативные имена: niisi.msk.ru t01.niisi.msk.ru mail mailhost loghost server server3 server3.systud.msk.su www www.systud.msk.su t01.systud.msk.suТип адреса хоста: 2Длина адреса хоста: 4Сетевые адреса хоста:193 232 173 1... Официальное имя хоста: t17Альтернативные имена: galatenkoТип адреса хоста: 2Длина адреса хоста: 4Сетевые адреса хоста:193 232 173 17...

Листинг 11.3. Фрагмент возможных результатов работы программы, осуществляющей последовательный доступ к сетевой базе данных о хостах - узлах сети.

К рассматриваемой базе возможен и случайный доступ по ключам - именам и адресам хостов с помощью функций gethostbyname() и gethostbyaddr(), однако они считаются устаревшими и из новой версии стандарта POSIX могут быть исключены. Вместо них предлагается использовать функции getnameinfo() и getaddrinfo() (см. пример 11.4).

#include <sys/socket.h>#include <netdb.h> void freeaddrinfo (struct addrinfo *ai); int getaddrinfo (const char *restrict nodename, const char *restrict servname, const struct addrinfo *restrict hints, struct addrinfo **restrict res); int getnameinfo (const struct sockaddr *restrict sa, socklen_t salen, char *restrict node, socklen_t nodelen, char *restrict service, socklen_t servicelen, int flags);

Листинг 11.4. Описание функций freeaddrinfo(), getaddrinfo(), getnameinfo().

Функция getaddrinfo() позволяет по имени узла сети (хоста) (аргумент nodename) и/или имени сетевого сервиса (servname) получить набор адресов сокетов и ассоциированную информацию, что дает возможность создать сокет для обращения к заданному сервису.

Если аргумент nodename отличен от пустого указателя, он способен задавать описательное имя или адресную цепочку. Для адресных семейств AF_INET и AF_UNSPEC (см. ниже описание аргумента hints) именем может служить имя хоста, а адресной цепочкой - стандартные для Internet адреса в точечных обозначениях (например, 193.232.173.17).

При пустом значении nodename подразумевается хост, локальный для вызывающего процесса.

Аргумент servname может задавать имя сервиса или (для адресных семейств AF_INET и AF_UNSPEC) десятичный номер порта. Пустое значение servname означает запрос сетевого адреса.

Аргумент hints позволяет передать дополнительную информацию об опрашиваемом сервисе - адресное семейство, тип сокета, протокол, флаги. Согласно стандарту, структура addrinfo, описанная в заголовочном файле <netdb.h>, должна содержать по крайней мере следующие поля.

int ai_flags; /* Входные флаги */ int ai_family; /* Адресное семейство сокета */ int ai_socktype; /* Тип сокета */ int ai_protocol; /* Протокол сокета */ socklen_t ai_addrlen; /* Длина адреса сокета */ struct sockaddr *ai_addr; /* Адрес сокета */ char *ai_canonname; /* Официальное имя узла сети */ struct addrinfo *ai_next; /* Указатель на следующий элемент списка */

При обращении к функции getaddrinfo() все поля структуры addrinfo, на которую указывает аргумент hints, кроме первых четырех (ai_flags, ai_family, ai_socktype, ai_protocol), должны быть нулевыми или равными NULL. Значение AF_UNSPEC в поле ai_family подразумевает, что вызывающего устроит любое адресное семейство. Аналогичный смысл имеют нулевые значения полей ai_socktype и ai_protocol. При hints, равном NULL, подразумевается AF_UNSPEC для ai_family и нулевые значения для других полей.

Из флагов, которые могут быть установлены в поле ai_flags, упомянем следующие.

AI_PASSIVE

Если значение аргумента nodename равно NULL, этот флаг игнорируется. В противном случае, если он указан, будет возвращен адрес сокета, предназначенного для принятия входящих соединений.

AI_CANONNAME

Данный флаг предписывает выяснить официальное имя узла сети.

AI_NUMERICHOST

Флаг означает, что хост задан адресной цепочкой, и не допускает использования какого-либо сервиса имен.

AI_NUMERICSERV

Флаг помечает, что сервис (аргумент servname) задан номером порта, и налагает запрет на обращение к какому-либо сервису имен.

Признаком успешного завершения функции getaddrinfo() является нулевой результат. В таком случае выходной аргумент res будет ссылаться на указатель на список структур типа addrinfo (связанных полем ai_next) - принадлежащие им значения полей ai_family, ai_socktype, ai_protocol пригодны для создания подходящих сокетов с помощью функции socket(), а значения ai_addr и ai_addrlen, в зависимости от флага AI_PASSIVE, могут служить аргументами функций connect() или bind(), применяемых к созданному сокету.

Функция freeaddrinfo() позволяет освободить память, занятую списком структур типа addrinfo и ассоциированными данными.

Функцию getnameinfo() можно считать обратной по отношению к getaddrinfo(). Аргумент sa - входной, он задает транслируемый адрес сокета (salen - размер структуры sockaddr). Аргументы node и service - выходные, задающие адреса областей памяти, куда помещаются, соответственно, имя узла и сервиса; размеры этих областей ограничены значениями nodelen и servicelen.

По умолчанию предполагается, что сокет имеет тип SOCK_STREAM, а кроме того, возвращается полное доменное имя хоста. Аргумент flags позволяет изменить подразумеваемое поведение. Если задан флаг NI_DGRAM, сокет считается датаграммным. При установленном флаге NI_NOFQDN возвращается короткое имя узла. Флаги NI_NUMERICHOST и NI_NUMERICSERV предписывают возвращать числовые цепочки для адресов хоста и сервиса, соответственно.

Обратим внимание на несколько технических деталей. При работе с адресами сокетов вместо родовой структуры типа sockaddr обычно используются более специализированные (описанные в заголовочном файле <netinet/in.h>) - sockaddr_in для адресного семейства AF_INET (IPv4) и sockaddr_in6 для AF_INET6 (IPv6). Первая из них, согласно стандарту POSIX-2001, должна содержать по крайней мере следующие поля (все с сетевым порядком байт).

sa_family_t sin_family; /* AF_INET */in_port_t sin_port; /* Номер порта */struct in_addr sin_addr; /* IP-адрес */

Структура типа sockaddr_in6 устроена несколько сложнее; мы не будем ее рассматривать.

Структуры типов sockaddr и sockaddr_in (или sockaddr_in6) мысленно накладываются друг на друга, а преобразование типов между ними выполняется по мере необходимости. Отметим также, что тип in_port_t эквивалентен uint16_t, структура типа in_addr содержит по крайней мере одно поле:

in_addr_t s_addr;тип in_addr_t эквивалентен uint32_t.

Техническую роль играют и функции преобразования IP-адресов из текстового представления в числовое и наоборот (см. пример 11.5).

#include <arpa/inet.h>in_addr_t inet_addr (const char *cp);char *inet_ntoa (struct in_addr in);int inet_pton (int af, const char *restrict src, void *restrict dst);const char *inet_ntop (int af, const void *restrict src, char *restrict dst, socklen_t size);

Листинг 11.5. Описание функций преобразования IP-адресов из текстового представления в числовое и наоборот.

Первые две функции манипулируют только адресами IPv4: inet_addr() преобразует текстовую цепочку cp (адрес в стандартных точечных обозначениях) в пригодное для использования в качестве IP-адреса целочисленное значение, inet_ntoa() выполняет обратное преобразование.

Вторая пара функций по сути аналогична первой, но имеет чуть более общий характер, так как способна преобразовывать адреса в формате IPv6. Первый аргумент этих функций, af, задает адресное семейство: AF_INET для IPv4 и AF_INET6 для IPv6. Буфер, на который указывает аргумент dst функции inet_pton() (в него помещается результат преобразования - IP-адрес в числовой двоичной форме с сетевым порядком байт), должен иметь длину не менее 32 бит для адресов IPv4 и 128 бит для IPv6.

Аргумент src функции inet_ntop(), возвращающей текстовое представление, указывает на буфер с IP-адресом в числовой форме с сетевым порядком байт. Аргумент size задает длину выходного буфера, на него указывает аргумент dst. Подходящими значениями, в зависимости от адресного семейства, могут служить INET_ADDRSTRLEN или INET6_ADDRSTRLEN.

Выше было отмечено, что преобразование значений типов uint16_t и uint32_t из хостового порядка байт в сетевой выполняется посредством функций htons() и htonl(); функции ntohs() и ntohl() осуществляют обратную операцию (см. пример 11.6).

#include <arpa/inet.h>uint32_t htonl (uint32_t hostlong);uint16_t htons (uint16_t hostshort);uint32_t ntohl (uint32_t netlong);uint16_t ntohs (uint16_t netshort);

Листинг 11.6. Описание функций преобразования целочисленных значений из хостового порядка байт в сетевой и наоборот.

Использование функции getaddrinfo() вместе с сопутствующими техническими деталями проиллюстрируем программой, показанной в пример 11.7. Возможные результаты ее выполнения приведены в пример 11.8.

#include <stdio.h>#include <netdb.h>#include <arpa/inet.h> int main (void) { struct addrinfo hints = {AI_CANONNAME, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; struct addrinfo *addr_res; if (getaddrinfo ("www", "http", &hints, &addr_res)!= 0) { perror ("GETADDRINFO"); } else { printf ("Результаты для сервиса http\n"); /* Пройдем по списку возвращенных структур */ do { printf ("Адрес сокета: Порт: %d IP-адрес: %s\n", ntohs (((struct sockaddr_in *) addr_res->ai_addr)->sin_port), inet_ntoa (((struct sockaddr_in *) addr_res->ai_addr)->sin_addr)); printf ("Официальное имя хоста: %s\n", addr_res->ai_canonname); } while ((addr_res = addr_res->ai_next)!= NULL); } return 0;}

Листинг 11.7. Пример программы, использующей функцию getaddrinfo().

Результаты для сервиса httpАдрес сокета: Порт: 80 IP-адрес: 193.232.173.1Официальное имя хоста: t01

Листинг 11.8. Возможный результат работы программы, использующей функцию getaddrinfo().

Завершая изложение серии технических моментов, укажем, что полезным дополнением к функциям getaddrinfo() и getnameinfo() является функция gai_strerror() (см. пример 11.9). Она возвращает текстовую цепочку, расшифровывающую коды ошибок, перечисленные в заголовочном файле <netdb.h>. Стандарт POSIX-2001 специфицирует следующие коды ошибок, имена которых говорят сами за себя: EAI_AGAIN, EAI_BADFLAGS, EAI_FAIL, EAI_FAMILY, EAI_MEMORY, EAI_NONAME, EAI_OVERFLOW, EAI_SERVICE, EAI_SOCKTYPE, EAI_SYSTEM.

#include <netdb.h>const char *gai_strerror (int ecode);

Листинг 11.9. Описание функции gai_strerror().

Если немного модифицировать приведенную выше программу (в пример 11.10 показан измененный фрагмент, где имя сервиса - "HTTP" - задано большими буквами), то в стандартный протокол с помощью функции gai_strerror() будет выдано содержательное диагностическое сообщение (см. пример 11.11). Отметим, что выдача функции perror() в данном случае невразумительна.

... int res; if ((res = getaddrinfo ("www", "HTTP", &hints, &addr_res))!= 0) { perror ("GETADDRINFO"); fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); } else { printf ("Результаты для сервиса HTTP\n");...

Листинг 11.10. Модифицированный фрагмент программы, использующей функции getaddrinfo() и gai_strerror().

GETADDRINFO: No such file or directoryGETADDRINFO: Servname not supported for ai_socktype

Листинг 11.11. Диагностические сообщения от функций perror() и gai_strerror(), выданные по результатам работы функции getaddrinfo().

Наряду с базой данных хостов (узлов сети) поддерживается база данных сетей с аналогичной логикой работы и набором функций (см. пример 11.12).

#include <netdb.h>void setnetent (int stayopen);struct netent *getnetent (void);struct netent *getnetbyaddr (uint32_t net, int type);struct netent *getnetbyname (const char *name);void endnetent (void);

Листинг 11.12. Описание функций доступа к базе данных сетей.

Функция getnetent() обслуживает последовательный доступ к базе, getnetbyaddr() осуществляет поиск по адресному семейству (аргумент type) и номеру net сети, а getnetbyname() выбирает сеть с заданным (официальным) именем. Структура типа netent, указатель на которую возвращается в качестве результата этих функций, согласно стандарту POSIX-2001, должна содержать по крайней мере следующие поля.

char *n_name; /* Официальное имя сети */ char **n_aliases; /* Массив указателей на альтернативные *//* имена сети, завершаемый пустым указателем */ int n_addrtype; /* Адресное семейство (тип адресов) сети */ uint32_t n_net; /* Номер сети (в хостовом порядке байт) */

Точно такой же программный интерфейс предоставляет база данных сетевых протоколов (см. пример 11.13).

#include <netdb.h>void setprotoent (int stayopen);struct protoent *getprotoent (void);struct protoent *getprotobyname (const char *name);struct protoent *getprotobynumber (int proto);void endprotoent (void);

Листинг 11.13. Описание функций доступа к базе данных сетевых протоколов.

Структура типа protoent содержит по крайней мере следующие поля.

char *p_name; /* Официальное имя протокола */ char **p_aliases; /* Массив указателей на альтернативные *//* имена протокола, завершаемый пустым *//* указателем */ int p_proto; /* Номер протокола */

В пример 11.14 показан пример программы, осуществляющей последовательный и случайный доступ к базе данных сетевых протоколов. пример 11.15 содержит фрагмент возможных результатов работы этой программы.

#include <stdio.h>#include <netdb.h> int main (void) { struct protoent *pht; char *pct; int i; setprotoent (1); while ((pht = getprotoent ())!= NULL) { printf ("Официальное имя протокола: %s\n", pht->p_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->p_aliases [i])!= NULL; i++) { printf (" %s\n", pct); } printf ("Номер протокола: %d\n\n", pht->p_proto); } if ((pht = getprotobyname ("ipv6"))!= NULL) { printf ("Номер протокола ipv6: %d\n\n", pht->p_proto); } else { fprintf (stderr, "Протокол ip в базе не найден\n"); } if ((pht = getprotobyname ("IPV6"))!= NULL) { printf ("Номер протокола IPV6: %d\n\n", pht->p_proto); } else { fprintf (stderr, "Протокол IPV6 в базе не найден\n"); } endprotoent (); return 0;}

Листинг 11.14. Пример программы, осуществляющей последовательный и случайный доступ к базе данных сетевых протоколов.

Официальное имя протокола: ipАльтернативные имена: IPНомер протокола: 0 Официальное имя протокола: icmpАльтернативные имена: ICMPНомер протокола: 1... Официальное имя протокола: tcpАльтернативные имена: TCPНомер протокола: 6... Официальное имя протокола: udpАльтернативные имена: UDPНомер протокола: 17... Официальное имя протокола: ipv6Альтернативные имена: IPv6Номер протокола: 41... Официальное имя протокола: ipv6-cryptАльтернативные имена: IPv6-CryptНомер протокола: 50... Официальное имя протокола: visaАльтернативные имена: VISAНомер протокола: 70... Официальное имя протокола: iso-ipАльтернативные имена: ISO-IPНомер протокола: 80... Официальное имя протокола: sprite-rpcАльтернативные имена: Sprite-RPCНомер протокола: 90... Официальное имя протокола: ipx-in-ipАльтернативные имена: IPX-in-IPНомер протокола: 111... Официальное имя протокола: fcАльтернативные имена: FCНомер протокола: 133 Номер протокола ipv6: 41 Протокол IPV6 в базе не найден

Листинг 11.15. Фрагмент возможных результатов работы программы, осуществляющей последовательный и случайный доступ к базе данных сетевых протоколов.

Еще одно проявление той же логики работы - база данных сетевых сервисов (см. пример 11.16).

#include <netdb.h>void setservent (int stayopen);struct servent *getservent (void);struct servent *getservbyname (const char *name, const char *proto);struct servent *getservbyport (int port, const char *proto);void endservent (void);

Листинг 11.16. Описание функций доступа к базе данных сетевых сервисов.

Обратим внимание на то, что в данном случае можно указывать второй аргумент поиска - имя протокола. Впрочем, значение аргумента proto может быть пустым указателем, и тогда поиск производится только по имени сервиса (функция getservbyname()) или номеру порта (getservbyport()), который должен быть задан с сетевым порядком байт.

Структура типа servent содержит по крайней мере следующие поля.

char *s_name; /* Официальное имя сервиса */ char **s_aliases; /* Массив указателей на альтернативные *//* имена сервиса, завершаемый пустым *//* указателем */ int s_port; /* Номер порта, соответствующий сервису *//* (в сетевом порядке байт) */ char *s_proto; /* Имя протокола для взаимодействия с *//* сервисом */

В пример 11.17 приведен пример программы, использующей функции доступа к базе данных сервисов, а также функции преобразования между хостовым и сетевым порядками байт. В пример 11.18 показан фрагмент возможных результатов работы этой программы.

#include <stdio.h>#include <netdb.h> int main (void) { struct servent *pht; char *pct; int i; setservent (1); while ((pht = getservent ())!= NULL) { printf ("Официальное имя сервиса: %s\n", pht->s_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->s_aliases [i])!= NULL; i++) { printf (" %s\n", pct); } printf ("Номер порта: %d\n", ntohs ((in_port_t) pht->s_port)); printf ("Имя протокола: %s\n\n", pht->s_proto); } if ((pht = getservbyport (htons ((in_port_t) 21), "udp"))!= NULL) { printf ("Официальное имя сервиса: %s\n", pht->s_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->s_aliases [i])!= NULL; i++) { printf (" %s\n", pct); } printf ("Номер порта: %d\n", ntohs ((in_port_t) pht->s_port)); printf ("Имя протокола: %s\n\n", pht->s_proto); } else { perror ("GETSERVBYPORT"); } if ((pht = getservbyport (htons ((in_port_t) 21), (char *) NULL))!= NULL) { printf ("Официальное имя сервиса: %s\n", pht->s_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->s_aliases [i])!= NULL; i++) { printf (" %s\n", pct); } printf ("Номер порта: %d\n", ntohs ((in_port_t) pht->s_port)); printf ("Имя протокола: %s\n\n", pht->s_proto); } else { perror ("GETSERVBYPORT"); } endservent (); return 0;}

Листинг 11.17. Пример программы, использующей функции доступа к базе данных сервисов, а также функции преобразования между хостовым и сетевым порядками байт.

... Официальное имя сервиса: ftp-dataАльтернативные имена:Номер порта: 20Имя протокола: tcp Официальное имя сервиса: ftp-dataАльтернативные имена:Номер порта: 20Имя протокола: udp Официальное имя сервиса: ftpАльтернативные имена:Номер порта: 21Имя протокола: tcp Официальное имя сервиса: ftp Альтернативные имена: fsp fspdНомер порта: 21Имя протокола: udp... Официальное имя сервиса: kerberosАльтернативные имена: kerberos5 krb5Номер порта: 88Имя протокола: tcp Официальное имя сервиса: kerberosАльтернативные имена: kerberos5 krb5Номер порта: 88Имя протокола: udp... Официальное имя сервиса: authАльтернативные имена: authentication tap identНомер порта: 113Имя протокола: tcp Официальное имя сервиса: authАльтернативные имена: authentication tap identНомер порта: 113Имя протокола: udp... Официальное имя сервиса: printerАльтернативные имена: spoolerНомер порта: 515Имя протокола: tcp Официальное имя сервиса: printerАльтернативные имена: spoolerНомер порта: 515Имя протокола: udp... Официальное имя сервиса: fidoАльтернативные имена:Номер порта: 60179Имя протокола: tcp Официальное имя сервиса: fidoАльтернативные имена:Номер порта: 60179Имя протокола: udp Официальное имя сервиса: ftpАльтернативные имена: fsp fspdНомер порта: 21Имя протокола: udp Официальное имя сервиса: ftpАльтернативные имена:Номер порта: 21Имя протокола: tcp

Листинг 11.18. Фрагмент возможных результатов работы программы, использующей функции доступа к базе данных сервисов, а также функции преобразования между хостовым и сетевым порядками байт.

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


Дата добавления: 2015-07-19; просмотров: 35 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
Создание и завершение процессов| Функции для работы с сокетами

mybiblioteka.su - 2015-2024 год. (0.016 сек.)