address.sin_port = htons(9734);
В сервер, благодаря применению константы INADDR_ANY, внесено изменение, позволяющее принимать запросы на соединение от любых IP-адресов.
Теперь, выполнив программы server3 и client3, вы увидите корректный номер порта, используемый для локального соединения:
$ netstat
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:
#include <netdb.h>
struct hostent *gethostbyaddr(const void* addr, size_t len, int type);
struct hostent* gethostbyname(const char* name);
Структура, возвращаемая этими функциями, должна как минимум содержать следующие элементы.
struct hostent {
char *h_name; /* Имя узла */
char **h_aliases; /* Перечень псевдонимов (nicknames) */
int h_addrtype; /* Тип адреса */
int h_length; /* Длина адреса в байтах */
char **h_addr_list /* Перечень адреса (сетевой порядок байтов) */
};
Если в базе данных нет элемента, соответствующего заданному узлу или адресу, информационные функции вернут пустой указатель.
Аналогично информацию, касающуюся сервисов и связанных номеров портов, можно получить с помощью информационных функций сервисов:
#include <netdb.h>
struct servent *getservbyname(const char *name, const char *proto);
struct servent *getservbyport(int port, const char *proto);
Параметр proto задает протокол, который будет применяться для подключения к сервису, либо "tcp" для TCP-соединений типа SOCK_STREAM, либо "udp" для UDP-дейтаграмм типа SOCK_DGRAM.
Структура servent содержит как минимум следующие элементы:
struct servent {
char *s_name; /* Имя сервиса */
char **s_aliases; /* Список псевдонимов (дополнительных имен) */
int s_port; /* Номер IP-порта */
char *s_proto; /* Тип сервиса, обычно "tcp" или "udp" */
}
Вы можете собрать воедино информацию о компьютере из базы данных сетевых узлов, вызвав функцию gethostbyname и выведя ее результаты. Учтите, что адрес необходимо преобразовать в соответствующий тип и перейти от сетевого упорядочивания к пригодной для вывода строке с помощью преобразования inet_ntoa, определенного следующим образом:
#include <arpa/inet.h>
char *inet_ntoa(struct in_addr in);
Функция преобразует адрес интернет-узла в строку формата четверки чисел с точками. В случае ошибки она возвращает -1, но в стандарте POSIX не определены конкретные ошибки. Еще одна новая функция, которую вы примените, — gethostname:
#include <unistd.h>
int gethostname(char *name, int name length);
Эта функция записывает имя текущего узла в строку, заданную параметром name. Имя узла будет нуль-терминированной строкой. Аргумент namelength содержит длину строкового имени и, если возвращаемое имя узла превысит эту длину, оно будет обрезано. Функция gethostname возвращает 0 в случае успешного завершения и -1 в случае ошибки. И снова ошибки в стандарте POSIX не определены.
Выполните упражнение 15.5.
Данная программа getname.c получает сведения о компьютере.
1. Как обычно, вставьте соответствующие заголовочные файлы и объявите переменные:
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char *host, **names, **addrs;