Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

19 FD_SET(connfd, &xset);

20 Select(connfd + 1, &rset, NULL, &xset, NULL);

21 if (FD_ISSET(connfd, &xset)) {

22 n = Recv(connfd, buff, sizeof(buff) - 1, MSG_OOB);

23 buff[n] =0; /* завершающий нуль */

24 printf("read OOB byte: %s\n", n, buff);

25 }

26 if (FD_ISSET(connfd, &rset)) {

27 if ((n = Read(connfd, buff, sizeof(buff) - 1)) == 0) {

28 printf("received EOF\n");

29 exit(0);

30 }

31 buff[n] = 0; /* завершающий нуль */

32 printf("read bytes: %s\n", n, buff);

33 }

34 }

35 }

15-20
Процесс вызывает функцию
select
, которая ожидает получения либо обычных данных (набор дескрипторов для чтения,
rset
), либо внеполосных (набор дескрипторов для обработки исключений,
xset
). В обоих случаях полученные данные выводятся.

Если мы запустим эту программу, а затем — программу для отправки, которая приведена в листинге 24.1, то столкнемся со следующей ошибкой:

freebsd4 % tcprecv02 9999

read 3 bytes: 123

read 1 OOB byte: 4

recv error: Invalid argument

Проблема заключается в том, что функция

select
будет сообщать об исключительной ситуации, пока процесс не считает данные, находящиеся за отметкой внеполосных данных (то есть после них [128, с. 530-531]). Мы не можем считывать внеполосные данные больше одного раза, так как после первого же их считывания ядро очищает буфер, содержащий один байт внеполосных данных. Когда мы вызываем функцию
recv
, устанавливая флаг
MSG_OOB
во второй раз, она возвращает ошибку
EINVAL
.

Чтобы решить эту проблему, нужно вызывать функцию

select
для проверки на наличие исключительной ситуации только после того, как будут приняты все обычные данные. В листинге 24.4 показана модифицированная версия принимающей программы из листинга 24.3. В этой версии описанный сценарий обрабатывается корректно.

Листинг 24.4. Модификация программы, приведенной в листинге 24.3. Функция select применяется для проверки исключительной ситуации корректным образом

//oob/tcprecv03.c

1 #include "unp.h"

2 int

3 main(int argc, char **argv)

4 {

5 int listenfd, connfd, n, justreadoob = 0;

6 char buff[100];

7 fd_set rset, xset;

8 if (argc == 2)

9 listenfd = Tcp_listen(NULL, argv[1], NULL);

10 else if (argc == 3)

11 listenfd = Tcp_1isten(argv[1], argv[2], NULL);

12 else

13 err_quit("usage: tcprecv03 [ <host> ] <port#>");

14 connfd = Accept(listenfd, NULL, NULL);

15 FD_ZERO(&rset);

16 FD_ZERO(&xset);

17 for (;;) {

18 FD_SET(connfd, &rset);

19 if (justreadoob == 0)

20 FD_SET(connfd, &xset);

21 Select(connfd + 1, &rset, NULL, &xset, NULL);

22 if (FD_ISSET(connfd, &xset)) {

23 n = Recv(connfd, buff, sizeof(buff) - 1, MSG_OOB);

24 buff[n] = 0; /* завершающий нуль */

  • Читать дальше
  • 1
  • ...
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: