Библиотека C во FreeBSD содержит много вспомогательных функций для программирования сокетов. К примеру, в нашем клиенте мы использовали точный IP адрес time.nist.gov. Но IP адрес нам не всегда известен. Даже, если мы знаем его, наша программа будет более гибкой, если мы дадим возможность пользователю вводить IP адрес или имя домена самостоятельно.
gethostbyname
Не существует способа передать имя домена напрямую к какой-либо функции для работы с сокетом. По этой причине C библиотека во FreeBSD содержит функции gethostbyname(3) и gethostbyname2(3), объявленные в файле netdb.h.
struct hostent * gethostbyname(const char *name); struct hostent * gethostbyname2(const char *name, int af);
Обе функции возвращают указатель на структуру hostent
,
содержащей достаточно информации о домене. Нам понадобится поле структуры h_addr_list[0]
, указывающее на h_length
байт правильного адреса, уже хранящегося в сетевом порядке байт.
Это позволит нам создать более гибкую, более полезную версию нашей программы daytime:
/* * daytime.c * * Programmed by G. Adam Stanislav * 19 June 2001 */ #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> int main(int argc, char *argv[]) { register int s; register int bytes; struct sockaddr_in sa; struct hostent *he; char buf[BUFSIZ+1]; char *host; if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return 1; } bzero(&sa, sizeof sa); sa.sin_family = AF_INET; sa.sin_port = htons(13); host = (argc > 1) ? (char *)argv[1] : "time.nist.gov"; if ((he = gethostbyname(host)) == NULL) { herror(host); return 2; } bcopy(he->h_addr_list[0],&sa.sin_addr, he->h_length); if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) { perror("connect"); return 3; } while ((bytes = read(s, buf, BUFSIZ)) > 0) write(1, buf, bytes); close(s); return 0; }
Теперь мы можем передать имя домена (или IP адрес) через командную строку. Программа будет пытаться соединиться
с указанным daytime сервером или по
умолчанию будет обращаться к time.nist.gov. Даже в последнем
случае использование gethostbyname
лучше нежели статическое
указание 192.43.244.18, т.к. даже при смене IP адреса мы все равно сможем найти этот хост.
Так как получение данных о времени с вашего локального сервера не займёт времени, вы можете запустить daytime дважды: один раз получить время с time.nist.gov, а второй раз со своей системы, а затем узнать насколько точное ваше системное время:
% daytime ; daytime localhost 52080 01-06-20 04:02:33 50 0 0 390.2 UTC(NIST) * 2001-06-20T04:02:35Z %
Как вы видите, моя система на две секунды опережала временную зону NIST.
getservbyname
Иногда вы можете быть не уверены в том, какой порт использует определённый сервис. В таких случаях может помочь функция getservbyname(3), также объявленная в netdb.h:
struct servent * getservbyname(const char *name, const char *proto);
Структура servent
содержит поле s_port
, содержащее соответствующий порт в сетевом порядке байт.
Если мы не знаем какой порт использует сервис daytime, мы можем найти его следующим образом:
struct servent *se; ... if ((se = getservbyname("daytime", "tcp")) == NULL { fprintf(stderr, "Cannot determine which port to use.\n"); return 7; } sa.sin_port = se->s_port;
Всё таки, обычно порт нам известен. Но если вы разрабатываете новый протокол, вы
можете тестировать его, используя неофициальный порт. Когда-нибудь вы зарегистрируйте
протокол и его порт (он должен появиться в вашем файле /etc/services, куда заглядывает функция getservbyname
). Вместо возвращения ошибки в вышеприведённом коде,
просто используйте временный номер порта. После того, как протокол появится в /etc/services, ваша программа будет находить её порт без
необходимости переписывать код.
Пред. | Начало | След. |
Основные функции для работы с сокетами | Уровень выше | Параллельные серверы |
Этот, и другие документы, могут быть скачаны с ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
По вопросам, связанным с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.
По вопросам, связанным с этой документацией, пишите <doc@FreeBSD.org>.
По вопросам, связанным с русским переводом документации, пишите в рассылку <frdp@FreeBSD.org.ua>.
Информация по подписке на эту рассылку находится на сайте проекта перевода.