Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Возвращает: непустой указатель в случае успешного выполнения, -1 в случае ошибки
Эта функция возвращает указатель на ту же структуру hostent
, которую мы описывали при рассмотрении функции gethostbyname
. Обычно в этой структуре нас интересует поле h_name
, каноническое имя узла.
Аргумент addr
не относится к типу char*
, но в действительности это указатель на структуру in_addr
, содержащую адрес IPv4. Поле len
— это длина структуры: 4 для адресов IPv4. Аргумент family
будет иметь значение AF_INET
.
В терминах DNS функция gethostbyaddr
запрашивает у сервера имен запись типа PTR в домене in-addr.arpa
.
11.5. Функции getservbyname и getservbyport
Службы, как и узлы, также часто идентифицируются по именам. Используя в нашем коде имя службы вместо номера порта, при условии, что имена служб сопоставляются номерам портов в некотором файле (обычно /etc/services
), мы получаем следующее преимущество. Если этой службе будет назначен другой номер порта, то нам будет достаточно изменить одну строку в файле /etc/services
, вместо того чтобы перекомпилировать все приложения. Следующая функция, getservbyname
, ищет службу по ее заданному имени.
Канонический список номеров портов, назначенных определенным службам, поддерживается IANA и располагается по адресу http://www.iana.org/assignments/port-numbers (см. раздел 2.9). Файл /etc/services чаще всего содержит некоторое подмножество списка IANA.
#include
struct servent *getservbyname(const char * servname , const char * protoname );
Возвращает: непустой указатель в случае успешного выполнения, NULL в случае ошибки
Функция возвращает указатель на следующую структуру:
struct servent {
char *s_name; /* официальное имя службы */
char **s_aliases; /* список псевдонимов */
int s_port; /* номер порта, записанный в сетевом порядке байтов */
char *s_proto; /* протокол, который нужно использовать */
};
Имя службы servname
должно быть указано обязательно. Если задан и протокол (то есть если protoname
— непустой указатель), то в структуре должен быть указан совпадающий протокол. Некоторые службы Интернета позволяют использовать и TCP, и UDP (например, DNS и все службы, представленные в табл. 2.1), в то время как другие поддерживают только один протокол (протоколу FTP требуется TCP). Если аргумент protoname
не задан и служба поддерживает несколько протоколов, то возвращаемый номер порта зависит от реализации. Обычно это не имеет значения, поскольку службы, поддерживающие множество протоколов, как правило, используют один и тот же номер порта для протоколов TCP и UDP, но вообще говоря это не гарантируется.
Более всего в структуре servent
нас интересует поле номера порта. Поскольку номер порта возвращается в сетевом порядке байтов, мы не должны вызывать функцию htons
при записи его в структуру адреса сокета.
Типичные вызовы этой функции могут быть такими:
struct servent *sptr;
sptr = getservbyname("domain", "udp"); /* DNS с использованием UDP */
sptr = getservbyname("ftp", "tcp"); /* FTP с использованием TCP */
sptr = getservbyname("ftp", NULL); /* FTP с использованием TCP */
sptr = getservbyname("ftp", "udp"); /* этот вызов приведет к ошибке */
Поскольку протоколом FTP поддерживается только TCP, второй и третий вызовы эквивалентны, а четвертый вызов приводит к ошибке. Вот соответствующие строки из файла /etc/services
:
freebsd % grep -e ^ftp -e ^domain /etc/services
ftp-data 20/tcp #File Transfer [Default Data]
ftp 21/tcp #File Transfer [Control]
domain 53/tcp #Domain Name Server
domain 53/udp #Domain Name Server
ftp-agent 574/tcp #FTP Software Agent System
ftp-agent 574/udp #FTP Software Agent System
ftps-data 989/tcp # ftp protocol, data, over TLS/SSL
ftps 990/tcp # ftp protocol, control, over TLS/SSL
Следующая функция, getservbyport
, ищет службу по заданному номеру порта и (не обязательно) протоколу.
#include
struct servent *getservbyport(int port , const char * protname );
Возвращает: непустой указатель в случае успешного выполнения, NULL в случае ошибки
Значение аргумента port
должно быть записано в сетевом порядке байтов. Типичные примеры вызова этой функции приведены ниже:
struct servent *sptr;
sptr = getservbyport(htons(53), "udp"); /* DNS с использованием UDP */
sptr = getservbyport(htons(21), "tcp"); /* FTP с использованием TCP */
sptr = getservbyport(htons(21), NULL); /* FTP с использованием TCP */
sptr = getservbyport(htons(21), "udp"); /* этот вызов приведет к ошибке */
Последний вызов оказывается неудачным, поскольку нет службы, использующей порт 21 с протоколом UDP.
Помните, что некоторые номера портов используются с TCP для одной службы, а с UDP — для совершенно другой, например:
freebsd % grep 514 /etc/services
shell 514/tcp cmd #like exec, but automatic
syslog 514/udp
Здесь показано, что порт 514 используется командой rsh
с TCP и демоном syslog
с UDP. Это характерно для портов 512-514.
Пример: использование функций gethostbyname и getservbyname
Теперь мы можем изменить код нашего TCP-клиента времени и даты, показанный в листинге 1.1, так, чтобы использовать функции gethostbyname
и getservbyname
и принимать два аргумента командной строки: имя узла и имя службы. Наша программа показана в листинге 11.2. Эта программа также демонстрирует желательное поведение при установлении соединения со всеми IP-адресами сервера на узле, имеющем несколько сетевых интерфейсов: попытки продолжаются до тех пор, пока соединение не будет успешно установлено или пока не будут перебраны все адреса.
Листинг 11.2. Наш клиент времени и даты, использующий функции gethostbyname и getservbyname
//names/daytimetcpcli1.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int sockfd, n;
6 char recvline[MAXLINE + 1];
7 struct sockaddr_in servaddr;
8 struct in_addr **pptr;
9 struct in_addr *inetaddrp[2];
10 struct in_addr inetaddr;
11 struct hostent *hp;
12 struct servent *sp;
13 if (argc != 3)
14 err_quit("usage: daytimetcpcli1 ");
15 if ((hp = gethostbyname(argv[1])) == NULL) {
16 if (inet_aton(argv[1], &inetaddr) == 0) {
17 err_quit("hostname error for %s: %s", argv[1],
18 hstrerror(h_errno));
19 } else {
20 inetaddrp[0] = &inetaddr;
21 inetaddrp[1] = NULL;
22 pptr = inetaddrp;
23 }
24 } else {
25 pptr = (struct in_addr**)hp->h_addr_list;
26 }
27 if ((sp = getservbyname(argv[2], "tcp")) == NULL)
28 err_quit("getservbyname error for %s", argv[2]);
29 for (; *pptr != NULL; pptr++) {
30 sockfd = Socket(AF_INET, SOCK_STREAM, 0);
31 bzero(&servaddr, sizeof(servaddr));
32 servaddr.sin_family = AF_INET;
33 servaddr.sin_port = sp->s_port;
34 memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
35 printf("trying %s\n", Sock_ntop((SA*)&servaddr, sizeof(servaddr)));
36 if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) == 0)
37 break; /* успешное завершение */
38 err_ret("connect error");
39 close(sockfd);
40 }
41 if (*pptr == NULL)
Интервал:
Закладка: