Добавить в цитаты Настройки чтения

Страница 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 с нулевым значением (означающим, что мы не ждем вообще).