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

ЖАНРЫ

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

Мы делаем сокет неблокируемым для функции

connect
, но никогда не переустанавливаем его в блокируемый режим, заданный по умолчанию. Это нормально, поскольку мы записываем в сокет только небольшое количество данных (команда GET следующей функции) и считаем, что эти данные занимают значительно меньше места, чем имеется в буфере отправки сокета. Даже если из-за установленного флага отсутствия блокировки при вызове функции
write
происходит частичное копирование, наша функция
writen
обрабатывает эту ситуацию. Если оставить сокет неблокируемым,
это не повлияет на последующее выполнение функций
read
, потому что мы всегда вызываем функцию
select
для определения того момента, когда сокет станет готов для чтения.

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

write_get_cmd
, посылающая серверу команду HTTP GET.

Листинг 16.12. Отправка команды HTTP GET серверу

//nonblock/write_get_cmd.c

1 #include "web.h"

2 void

3 write_get_cmd(struct file *fptr)

4 {

5 int n;

6 char line[MAXLINE];

7 n = snprintf(line, sizeof(line), GET_CMD, fptr->f_name);

8 Writen(fptr->f_fd, line, n);

9 printf("wrote %d bytes for %s\n", n, fptr->f_name);

10 fptr->f_flags = F_READING; /* сброс F_CONNECTING */

11 FD_SET(fptr->f_fd, &rset); /* прочитаем ответ сервера */

12 if (fptr->f_fd > maxfd)

13 maxfd = fptr->f_fd;

14 }

Создание команды и ее отправка

7-9
Команда создается и пишется в сокет.

Установка флагов

10-13
Устанавливается флаг
F_READING
, при этом также сбрасывается флаг
F_CONNECTING
(если он установлен). Это указывает основному циклу, что данный дескриптор готов для ввода. Также включается дескриптор в наборе чтения, и при необходимости обновляется значение
maxfd
.

Теперь мы возвращаемся в функцию

main
, показанную в листинге 16.13, начиная с того места, где закончили в листинге 16.9. Это основной цикл программы: пока имеется ненулевое количество файлов для обработки (значение
nlefttoread
больше нуля), устанавливается, если это возможно, другое соединение и затем вызывается функция
select
для всех активных дескрипторов, обрабатывающая как завершение неблокируемых соединений, так и прием данных.

Можем ли мы инициировать другое соединение?

24-35
Если мы не дошли до заданного предела одновременных соединений и есть дополнительные соединения, которые нужно установить, мы ищем еще не обработанный
файл (на него указывает нулевое значение
f_flags
) и вызываем функцию
start_connect
для инициирования соединения. Число активных соединений увеличивается на единицу (
nconn
), а число соединений, которые нужно установить, на единицу уменьшается (
nlefttoconn
).

Функция select: ожидание событий

36-37
Функция
select
ожидает готовности сокета либо для чтения, либо для записи. Дескрипторы, для которых в настоящий момент происходит установление соединения (неблокируемая функция
connect
находится в процессе выполнения), будут включены в обоих наборах, в то время как дескрипторы с завершенным соединением, ожидающие данных от сервера, будут включены только в наборе чтения.

Листинг 16.13. Основной цикл функции main

//nonblock/web.c

24 while (nlefttoread > 0) {

25 while (nconn < maxnconn && nlefttoconn > 0) {

26 /* find a file to read */

27 for (i =0; i < nfiles; i++)

28 if (file[i].f_flags == 0)

29 break;

30 if (i == nfiles)

31 err_quit("nlefttoconn = %d but nothing found", nlefttoconn);

32 start_connect(&file[i]);

33 nconn++;

34 nlefttoconn--;

35 }

36 rs = rset:

37 ws = wset;

38 n = Select(maxfd + 1, &rs, &ws, NULL, NULL);

39 for (i = 0; i < nfiles; i++) {

40 flags = file[i].f_flags;

41 if (flags == 0 || flags & F_DONE)

42 continue;

43 fd = file[i].f_fd;

44 if (flags & F_CONNECTING &&

45 (FD_ISSET(fd, &rs) || FD_ISSET(fd, &ws))) {

46 n = sizeof(error);

47 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n) < 0 ||

48 error != 0) {

49 err_ret("nonblocking connect failed

50 for %s", file[i].f_name);

51 }

52 /* соединение установлено */

53 printf("connection established for %s\n", file[i].f_name);

54 FD_CLR(fd, &wset); /* отключаем запись в этот сокет */

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