Литмир - Электронная Библиотека
Содержание  
A
A

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 <i>sockfd</i>);

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

ПРИМЕЧАНИЕ

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

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

SIOCATMARK
функции
ioctl
.

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

//lib/sockatmark.c

1 #include &quot;unp.h&quot;

2 int

3 sockatmark(int fd)

4 {

5  int flag;

6  if (ioctl(fd, SIOCATMARK, &amp;flag) &lt; 0)

7   return (-1);

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

9 }

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

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

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

Далее мы приводим простой пример, иллюстрирующий следующие две особенности отметки внеполосных данных:

1. Отметка внеполосных данных всегда указывает на один байт дальше конечного байта обычных данных. Это означает, что, когда внеполосные данные получены вместе с обычными, функция

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

2. Операция считывания всегда останавливается на отметке внеполосных данных [128, с. 519–520]. Это означает, что если в приемном буфере сокета 100 байт, но только 5 из них расположены перед отметкой внеполосных данных, то когда процесс выполнит функцию

read
, запрашивая 100 байт, возвратятся только 5 байт, расположенные до этой отметки. Эта вынужденная остановка на отметке позволяет процессу вызвать функцию
sockatmark
, которая определит, находится ли указатель буфера на отметке внеполосных данных.

В листинге 24.6 показана наша программа отправки. Она посылает три байта обычных данных, один байт внеполосных данных, а затем еще один байт обычных данных. Паузы между этими операциями отсутствуют.

В листинге 24.7 показана принимающая программа. В ней не используется ни функция

select
, ни сигнал
SIGURG
. Вместо этого в ней вызывается функция
sokatmark
, определяющая положение байта внеполосных данных.

Листинг 24.6. Программа отправки

//oob/tcpsen04.c

 1 #include &quot;unp.h&quot;

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int sockfd;

 6  if (argc != 3)

 7   err_quit(&quot;usage: tcpsend04 &lt;host&gt; &lt;port#&gt;&quot;);

 8  sockfd = Tcp_connect(argv[1], argv[2]);

 9  Write(sockfd, &quot;123&quot;, 3);

10  printf(&quot;wrote 3 bytes of normal data\n&quot;);

11  Send(sockfd, &quot;4&quot;, 1, MSG_OOB);

12  printf(&quot;wrote 1 byte of OOB data\n&quot;);

272
{"b":"225366","o":1}