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

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

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

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 "unp.h"

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int sockfd;

 6  if (argc != 3)

 7   err_quit("usage: tcpsend04 <host> <port#>");

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

 9  Write(sockfd, "123", 3);

10  printf("wrote 3 bytes of normal data ");

11  Send(sockfd, "4", 1, MSG_OOB);

12  printf("wrote 1 byte of OOB data ");

13  Write(sockfd, "5", 1);

14  printf("wrote 1 byte of normal data ");

15  exit(0);

16 }

Листинг 24.7. Принимающая программа, в которой вызывается функция sokatmark

//oob/tcprecv04.c

 1 #include "unp.h"

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int listenfd, connfd, n, on = 1;

 6  char buff[100];

 7  if (argc == 2)

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

 9  else if (argc == 3)

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

11  else

12   err_quit("usage- tcprecv04 [ <host> ] <port#>");

13  Setsockopt(listenfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));

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

15  sleep(5);

16  for (;;) {

17   if (Sockatmark(connfd))

18    printf("at OOB mark ");

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

20    printf("received EOF ");

21    exit(0);

22   }

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

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

25  }

26 }

Включение параметра сокета SO_OOBINLINE

13 Мы хотим принимать внеполосные данные вместе с обычными данными, поэтому нам нужно включить параметр SO_OOBINLINE. Но если мы будем ждать, когда выполнится функция accept и установит этот параметр для присоединенного сокета, трехэтапное рукопожатие завершится и внеполосные данные могут уже прибыть. Поэтому нам нужно установить этот параметр еще для прослушиваемого сокета, помня о том, что все параметры прослушиваемого сокета наследуются присоединенным сокетом (см. раздел 7.4).

Вызов функции sleep после вызова функции accept

14-15 После того как выполнена функция accept, получатель переходит в спящее состояние, что позволяет получить все данные, посланные отправителем. Это позволяет нам продемонстрировать, что функция read останавливается на отметке внеполосных данных, даже если в приемном буфере сокета имеются дополнительные данные.

Считывание всех отправленных данных

16-25 В программе имеется цикл, в котором вызывается функция read и выводятся полученные данные. Но перед вызовом функции read функция sockatmark проверяет, находится ли указатель буфера на отметке внеполосных данных.

После выполнения этой программы мы получаем следующий результат:

freebsd4 % tcprecv04 6666

read 3 bytes: 123

at OOB mark

read 2 bytes: 45

received EOF

Хотя принимающий TCP получил все посланные данные, первый вызов функции read возвращает только три байта, так как была обнаружена отметка внеполосных данных. Следующий считанный байт — это байт, содержащий внеполосные данные (его значение равно 4), так как мы дали ядру указание поместить внеполосные данные вместе с обычными.

Данный текст является ознакомительным фрагментом.