Чтение онлайн

ЖАНРЫ

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

21 maxfd = -1;

22 nlefttoread = nlefttoconn = nfiles;

23 nconn = 0;

Обработка аргументов командной строки

11-17
Структуры
file
заполняются соответствующей информацией из аргументов командной строки.

Чтение домашней страницы

18
Функция
home_page
, которую мы показываем в следующем листинге, создает соединение TCP, посылает команду серверу и затем читает домашнюю страницу. Это первое
соединение, которое выполняется самостоятельно, до того как мы начнем устанавливать параллельные соединения.

Инициализация глобальных переменных

19-23
Инициализируются два набора дескрипторов, по одному для чтения и для записи.
maxfd
— это максимальный дескриптор для функции
select
(который мы инициализируем значением -1, поскольку дескрипторы неотрицательны),
nlefttoread
— число файлов, которые осталось прочитать (когда это значение становится нулевым, чтение заканчивается),
nlefttoconn
— это количество файлов, для которых пока еще требуется соединение TCP, a
nconn
— это число соединений, открытых в настоящий момент (оно никогда не может превышать первый аргумент командной строки).

В листинге 16.10 показана функция

home_page
, вызываемая один раз, когда начинается выполнение функции main.

Листинг 16.10. Функция home_page

//nonblock/home_page.c

1 #include "web.h"

2 void

3 home_page(const char *host, const char *fname)

4 {

5 int fd, n;

6 char line[MAXLINE];

7 fd = Tcp_connect(host, SERV); /* блокируемая функция connect */

8 n = snprintf(line, sizeof(line), GET_CMD, fname);

9 Writen(fd, line, n);

10 for (;;) {

11 if ((n = Read(fd, line, MAXLINE)) == 0)

12 break; /* сервер закрыл соединение */

13 printf("read %d bytes of home page\n", n);

14 /* обрабатываем полученные данные */

15 }

16 printf("end-of-file on home page\n");

17 Close(fd);

18 }

Установление соединения с сервером

7
Наша функция
tcp_connect
устанавливает соединение с сервером.

Отправка команды HTTP серверу, чтение ответа

8-17
Запускается команда HTTP
GET
для домашней страницы (часто обозначается символом
/
). Читается ответ (с ответом мы в данном случае ничего не делаем), и соединение закрывается.

Следующая функция,

start_connect
, показанная в листинге 16.11, инициирует вызов неблокируемой функции connect.

Листинг 16.11.

Инициирование неблокируемой функции connect

//nonblock/start_connect.c

1 #include "web.h"

2 void

3 start_connect(struct file *fptr)

4 {

5 int fd, flags, n;

6 struct addrinfo *ai;

7 ai = Host_serv(fptr->f_host, SERV, 0, SOCK_STREAM);

8 fd = Socket(ai->ai_family; ai->ai_socktype, ai->ai_protocol);

9 fptr->f_fd = fd;

10 printf("start_connect for %s, fd %d\n", fptr->f_name, fd);

11 /* отключаем блокирование сокета */

12 flags = Fcntl(fd, F_GETFL, 0);

13 Fcntl(fd, F_SETFL, flags | O_NONBLOCK);

14 /* инициируем неблокируемое соединение с сервером */

15 if ((n = connected, ai->ai_addr, ai->ai_addrlen)) < 0) {

16 if (errno != EINPROGRESS)

17 err_sys("nonblocking connect error");

18 fptr->f_flags = F_CONNECTING;

19 FD_SET(fd, &rset); /* включаем дескриптор сокета в наборе чтения

и записи */

20 FD_SET(fd, &wset);

21 if (fd > maxfd)

22 maxfd = fd;

23 } else if (n >= 0) /* соединение уже установлено */

24 write_get_cmd(fptr); /* отправляем команду GET серверу */

25 }

Создание сокета, отключение блокировки сокета

7-13
Мы вызываем нашу функцию
host_serv
для поиска и преобразования имени узла и имени службы. Она возвращает указатель на массив структур
addrinfo
. Мы используем только первую структуру. Создается сокет TCP, и он становится неблокируемым.

Вызов неблокируемой функции connect

14-22
Вызывается неблокируемая функция
connect
, и флагу файла присваивается значение
F_CONNECTING
. Включается дескриптор сокета и в наборе чтения, и в наборе записи, поскольку функция
select
будет ожидать любого из этих условий как указания на то, что установление соединения завершилось. При необходимости мы также обновляем значение
maxfd
.

Обработка завершения установления соединения

23-24
Если функция
connect
успешно завершается, значит, соединение уже установлено, и функция
write_get_cmd
(она показана в следующем листинге) посылает команду серверу.

Поделиться с друзьями: