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

ЖАНРЫ

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

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; /* завершающий нуль */

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

26 justreadoob = 1;

27 FD_CLR(connfd, &xset);

28 }

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

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

31 printf("received EOF\n");

32 exit(0);

33 }

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

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

36 justreadoob = 0;

37 }

38 }

39 }

5
Мы объявляем новую переменную с именем
justreadoob
, которая указывает, какие данные мы считываем — внеполосные или обычные. Этот флаг определяет, нужно ли вызывать функцию
select
для проверки на наличие исключительной ситуации.

26-27
Когда мы устанавливаем флаг
justreadoob
, мы также должны выключить бит соответствующего дескриптора в наборе для проверки исключительных ситуаций.

Теперь программа работает так, как мы ожидали.

24.3. Функция sockatmark

С приемом внеполосных данных всегда связана так называемая отметка внеполосных данных( out-of-bandmark). Это позиция в потоке обычных данных на стороне отправителя, соответствующая тому моменту; когда посылающий процесс отправляет байт, содержащий внеполосные данные. Считывая данные из сокета, принимающий процесс путем вызова функции

sockatmark
определяет, находится ли он в данный момент на этой отметке.

#include <sys/socket.h>

int sockatmark(int sockfd);

Возвращает: 1, если находится на отметке внеполосных данных: 0, если не на отметке; -1 в случае ошибки

ПРИМЕЧАНИЕ

Эта функция появилась в POSIX. Разработчики стандарта POSIX стремятся заменить отдельными функциями все вызовы ioctl с различными параметрами.

В листинге 24.5 показана реализация этой функции с помощью поддерживаемого в большинстве систем параметра

SIOCATMARK
функции
ioctl
.

Листинг 24.5. Функция sockatmark реализована с использованием функции ioctl

//lib/sockatmark.c

1 #include "unp.h"

2 int

3 sockatmark(int fd)

4 {

5 int flag;

6 if (ioctl(fd, SIOCATMARK, &flag) < 0)

7 return (-1);

8 return (flag != 0 ? 1 : 0);

9 }

Отметка внеполосных данных применима независимо от того, как принимающий процесс получает внеполосные данные: вместе с обычными данными (параметр сокета

SO_OOBINLINE
) или отдельно (флаг
MSG_OOB
). Отметка внеполосных данных часто используется для того, чтобы принимающий процесс мог интерпретировать получаемые данные специальным образом до тех пор, пока он не дойдет до этой отметки.

Пример: особенности отметки внеполосных данных

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