Книга: UNIX: разработка сетевых приложений

Пример: аргументы типа «значение-результат»

Пример: аргументы типа «значение-результат»

В листинге 4.2 представлен измененный код из листинга 1.5 (вывод IP-адреса и номера порта клиента), обрабатывающий аргумент типа «значение-результат» функции accept.

Листинг 4.2. Сервер определения времени и даты, сообщающий IP-адрес и номер порта клиента

//intro/daytimetcpsrv1.c
 1 #include "unp.h"
 2 #include <time.h>
 3 int
 4 main(int argc, char **argv)
 5 {
 6  int listenfd, connfd;
 7  socklen_t len;
 8  struct sockaddr_in servaddr, cliaddr;
 9  char buff[MAXLINE];
10  time_t ticks;
11  listenfd = Socket(AF_INET, SOCK_STREAM, 0);
12  bzero(&servaddr, sizeof(servaddr));
13  servaddr.sin_family = AF_INET;
14  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
15  servaddr.sin_port = htons(13); /* сервер времени и даты */
16  Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
17  Listen(listenfd, LISTENQ);
18  for (;;) {
19   len = sizeof(cliaddr);
20   connfd = Accept(listenfd, (SA*)&cliaddr, &len);
21   printf("connection from %s, port %dn",
22    Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff));
23   ntohs(cliaddr.sin_port));
24   ticks = time(NULL);
25   snprintf(buff, sizeof(buff), "% 24srn", ctime(&ticks));
26   Write(connfd, buff, strlen(buff));
27   Close(connfd);
28  }
29 }

Новые объявления

7-8 Мы определяем две новых переменных: len, которая будет переменной типа «значение-результат», и cliaddr, которая будет содержать адрес протокола клиента.

Принятие соединения и вывод адреса клиента

19-23 Мы инициализируем переменную len, присвоив ей значение, равное размеру структуры адреса сокета, и передаем указатель на структуру cliaddr и указатель на len в качестве второго и третьего аргументов функции accept. Мы вызываем функцию inet_ntop (см. раздел 3.7) для преобразования 32-битового IP-адреса в структуре адреса сокета в строку ASCII (точечно-десятичную запись), а затем вызываем функцию ntohs (см. раздел 3.4) для преобразования сетевого порядка байтов в 16-битовом номере порта в порядок байтов узла.

ПРИМЕЧАНИЕ

При вызове функции sock_ntop вместо inet_ntop наш сервер станет меньше зависеть от протокола, однако он все равно зависит от IPv4. Мы покажем версию этого сервера, не зависящего от протокола, в листинге 11.7.

Если мы запустим наш новый сервер, а затем запустим клиент на том же узле, то дважды соединившись с сервером, мы получим от клиента следующий вывод:

solaris % daytimetcpcli 127.0.0.1
Thu Sep 11 12:44:00 2003
solaris % daytimetcpcli 192.168.1.20
Thu Sep 11 12:44:09 2003

Сначала мы задаем IP-адрес сервера как адрес закольцовки на себя (loopback address) (127.0.0.1), а затем как его собственный IP-адрес (192.168.1.20). Вот соответствующий вывод сервера:

solaris # daytimetcpsrv1
connection from 127.0.0.1, port 43388
connection from 192.168.1.20, port 43389

Обратите внимание на то, что происходит с IP-адресом клиента. Поскольку наш клиент времени и даты (см. листинг 1.1) не вызывает функцию bind, как сказано в разделе 4.4, ядро выбирает IP-адрес отправителя, основанный на используемом исходящем интерфейсе. В первом случае ядро задает IP-адрес равным адресу закольцовки, во втором случае — равным IP-адресу интерфейса Ethernet. Кроме того, мы видим, что динамически назначаемый порт, выбранный ядром Solaris, — это 33 188, а затем 33 189 (см. рис. 2.10).

Наконец, заметьте, что приглашение интерпретатора команд изменилось на знак # — это приглашение к вводу команды для привилегированного пользователя. Наш сервер должен обладать правами привилегированного пользователя, чтобы с помощью функции bind связать зарезервированный порт 13. Если у нас нет прав привилегированного пользователя, вызов функции bind оказывается неудачным:

solaris % daytimetcpsrv1
bind error: Permission denied

Оглавление книги


Генерация: 1.256. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз