Шрифт:
Следующая функция,
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
(она показана в следующем листинге) посылает команду серверу. Мы делаем сокет неблокируемым для функции
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];