Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2557 / 712 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 11:

Сетевые средства

Функция 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.

Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?