Страница 183 из 399
■ В Беркли-реализациях (а также POSIX) имеются два следующих правила, относящихся к функции select и неблокируемой функции co
Эти два правила в отношении функции select выпадают из общего ряда наших правил из раздела 6.3 относительно условий, при которых дескриптор становится готовым для чтения или записи. В сокет TCP можно записывать, если достаточно места в буфере отправки (что всегда будет выполнено в случае присоединенного сокета, поскольку мы еще ничего не записали в сокет) и сокет является присоединенным (что выполняется, только когда завершено трехэтапное рукопожатие). При наличии ошибки, ожидающей обработки, появляется возможность читать из сокета и записывать в сокет.
С неблокируемыми функциями co
16.4. Неблокируемая функция co
В листинге 16.7 показана наша функция co
if (co
err_sys("co
Первые три аргумента являются обычными аргументами функции co
Листинг 16.7. Неблокируемая функция co
//lib/co
1 #include "unp.h"
2 int
3 co
4 {
5 int flags, n, error;
6 socklen_t len;
7 fd_set rset, wset;
8 struct timeval tval;
9 flags = Fcntl(sockfd, F_GETFL, 0);
10 Fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
11 error = 0;
12 if ((n = co
13 if (errno != EINPROGRESS)
14 return (-1);
15 /* Пока соединение устанавливается, мы можем заняться чем-то другим */
16 if (n == 0)
17 goto done; /* функция co
18 FD_ZERO(&rset);
19 FDSET(sockfd, &rset);
20 wset = rset;
21 tval.tv_sec = nsec;
22 tval.tv_usec = 0;
23 if ((n = Select(sockfd + 1, &rset, &wset, NULL,
24 nsec ? &tval : NULL)) == 0) {
25 close(sockfd); /* тайм-аут */
26 errno = ETIMEDOUT;
27 return (-1);
28 }
29 if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
30 len = sizeof(error);
31 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
32 return (-1); /*в Solaris ошибка, ожидающая обработки */
33 } else
34 err_quit("select error: sockfd not set");
35 done:
36 Fcntl(sockfd, F_SETFL, flags); /* восстанавливаем флаги, задающие статус файла */
37 if (error) {
38 close(sockfd); /* на всякий случай */
39 errno = error;
40 return (-1);
41 }
42 return (0);
43 }
9-10 Мы вызываем функцию fcntl, которая делает сокет неблокируемым.
11-14 Мы вызываем неблокируемую функцию co
15 На этом этапе мы можем делать все, что захотим, ожидая завершения установления соединения.
16-17 Если неблокируемая функция co
18-24 Мы вызываем функцию select и ждем, когда сокет будет готов либо для чтения, либо для записи. Мы обнуляем rset, включаем бит, соответствующий sockfd в этом наборе дескрипторов и затем копируем rset в wset. Это присваивание, возможно, является структурным присваиванием, поскольку обычно наборы дескрипторов представляются как структуры. Далее мы инициализируем структуру timeval и затем вызываем функцию select. Если вызывающий процесс задает четвертый аргумент нулевым (что соответствует использованию тайм-аута по умолчанию), следует задать в качестве последнего аргумента функции select пустой указатель, а не структуру timeval с нулевым значением (означающим, что мы не ждем вообще).