Читать интересную книгу Основы программирования в Linux - Мэтью Нейл

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 265 266 267 268 269 270 271 272 273 ... 324

Для того чтобы компьютеры разных типов могли согласовать значения многобайтовых целых чисел, передаваемых по сети, необходимо определить сетевой порядок передачи байтов. Перед передачей данных клиентские и серверные программы должны преобразовать собственное внутреннее представление целых чисел в соответствии с принятым в сети порядком следования байтов. Делается это с помощью функций, определенных в заголовочном файле netinet/in.h. К ним относятся следующие:

<b>#include &lt;netinet/in.h&gt;</b>

<b>unsigned long int htonl(unsigned long int hostlong);</b>

<b>unsigned short int htons(unsigned short int hostshort);</b>

<b>unsigned long int ntohl(unsigned long int netlong);</b>

<b>unsigned short int ntohs(unsigned short int netshort);</b>

Эти функции преобразуют 16- и 32-разрядные целые из внутреннего формата в сетевой порядок следования байтов и обратно. Их имена соответствуют сокращенному названию выполняемых преобразований, например "host to network, long" (htonl, компьютерный в сетевой, длинные целые) и "host to network, short" (htons, компьютерный в сетевой, короткие целые). Компьютерам, у которых порядок следования байтов соответствует сетевому, эти функции предоставляют пустые операции.

Для обеспечения корректного порядка следования при передаче 16-разрядного целого числа ваши сервер и клиент должны применить эти функции к адресу порта. В программу server3.c следует внести следующие изменения:

<i>server_address.sin_addr_s_addr = htonl(INADDR_ANY);</i>

<i>server_address.sin_port = htons(9734);</i>

Результат, возвращаемый функцией inet_addr(&quot;127.0.0.1&quot;), преобразовывать не нужно, потому что в соответствии со своим определением она возвращает результат с сетевым порядком следования байтов. В программу client3.c необходимо внести следующее изменение:

<i>address.sin_port = htons(9734);</i>

В сервер, благодаря применению константы INADDR_ANY, внесено изменение, позволяющее принимать запросы на соединение от любых IP-адресов.

Теперь, выполнив программы server3 и client3, вы увидите корректный номер порта, используемый для локального соединения:

$ <b>netstat</b>

Active Internet connections

Proto Recv-Q Send-Q Local Address  Foreign Address (State)   User

tcp        1      0 localhost:9734 localhost:1175  TIME_WAIT root

Примечание

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

Сетевая информация

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

Если у вас есть на это право, можно добавить свой сервер к списку известных сервисов в файл /etc/services, который назначает имена номерам портов, так что клиенты могут использовать вместо номеров символические имена сервисов.

Точно так же зная имя компьютера, можно определить IP-адрес, вызвав функции базы данных сетевых узлов (host database), которые найдут эти адреса. Делают они это, обращаясь за справкой к конфигурационным файлам, например, etc/hosts или к сетевым информационным сервисам, таким как NIS (Network Information Services (сервисы сетевой информации), ранее известным как Yellow Pages (желтые страницы)) и DNS (Domain Name Service, служба доменных имен).

Функции базы данных сетевых узлов или хостов (Host database) объявлены в заголовочном файле интерфейса netdb.h:

<b>#include &lt;netdb.h&gt;</b>

<b>struct hostent *gethostbyaddr(const void* addr, size_t len, int type);</b>

<b>struct hostent* gethostbyname(const char* name);</b>

Структура, возвращаемая этими функциями, должна как минимум содержать следующие элементы.

<b>struct hostent {</b>

<b> char *h_name;      /* Имя узла */</b>

<b> char **h_aliases;  /* Перечень псевдонимов (nicknames) */</b>

<b> int h_addrtype;    /* Тип адреса */</b>

<b> int h_length;      /* Длина адреса в байтах */</b>

<b> char **h_addr_list /* Перечень адреса (сетевой порядок байтов) */</b>

<b>};</b>

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

Аналогично информацию, касающуюся сервисов и связанных номеров портов, можно получить с помощью информационных функций сервисов:

<b>#include &lt;netdb.h&gt;</b>

<b>struct servent *getservbyname(const char *name, const char *proto);</b>

<b>struct servent *getservbyport(int port, const char *proto);</b>

Параметр proto задает протокол, который будет применяться для подключения к сервису, либо "tcp" для TCP-соединений типа SOCK_STREAM, либо "udp" для UDP-дейтаграмм типа SOCK_DGRAM.

Структура servent содержит как минимум следующие элементы:

<b>struct servent {</b>

<b> char *s_name;     /* Имя сервиса */</b>

<b> char **s_aliases; /* Список псевдонимов (дополнительных имен) */</b>

<b> int s_port;       /* Номер IP-порта */</b>

<b> char *s_proto;    /* Тип сервиса, обычно &quot;tcp&quot; или &quot;udp&quot; */</b>

<b>}</b>

Вы можете собрать воедино информацию о компьютере из базы данных сетевых узлов, вызвав функцию gethostbyname и выведя ее результаты. Учтите, что адрес необходимо преобразовать в соответствующий тип и перейти от сетевого упорядочивания к пригодной для вывода строке с помощью преобразования inet_ntoa, определенного следующим образом:

<b>#include &lt;arpa/inet.h&gt;</b>

<b>char *inet_ntoa(struct in_addr in);</b>

1 ... 265 266 267 268 269 270 271 272 273 ... 324
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Основы программирования в Linux - Мэтью Нейл.

Оставить комментарий