UNIX: разработка сетевых приложений
13 Write(sockfd, "5", 1);14 printf("wrote 1 byte of normal data\n");15 exit(0);16 }Листинг 24.7. Принимающая программа, в которой вызывается функция sokatmark
//oob/tcprecv04.c1 #include "unp.h"2 int3 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 else12 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\n");19 if ((n = Read(connfd, buff, sizeof(buff) - 1)) == 0) {20 printf("received EOF\n");21 exit(0);22 }23 buff[n] = 0; /* завершающий нуль */24 printf("read %d bytes: %s\n", n; buff);25 }26 }Включение параметра сокета SO_OOBINLINEМы хотим принимать внеполосные данные вместе с обычными данными, поэтому нам нужно включить параметр13. Но если мы будем ждать, когда выполнится функция accept и установит этот параметр для присоединенного сокета, трехэтапное рукопожатие завершится и внеполосные данные могут уже прибыть. Поэтому нам нужно установить этот параметр еще для прослушиваемого сокета, помня о том, что все параметры прослушиваемого сокета наследуются присоединенным сокетом (см. раздел 7.4).SO_OOBINLINEВызов функции sleep после вызова функции acceptПосле того как выполнена функция14-15, получатель переходит в спящее состояние, что позволяет получить все данные, посланные отправителем. Это позволяет нам продемонстрировать, что функция read останавливается на отметке внеполосных данных, даже если в приемном буфере сокета имеются дополнительные данные.acceptСчитывание всех отправленных данныхВ программе имеется цикл, в котором вызывается функция16-25и выводятся полученные данные. Но перед вызовом функцииreadфункцияreadпроверяет, находится ли указатель буфера на отметке внеполосных данных.sockatmarkПосле выполнения этой программы мы получаем следующий результат:
freebsd4 % <b>tcprecv04 6666</b>read 3 bytes: 123at OOB markread 2 bytes: 45received EOFХотя принимающий TCP получил все посланные данные, первый вызов функции
возвращает только три байта, так как была обнаружена отметка внеполосных данных. Следующий считанный байт — это байт, содержащий внеполосные данные (его значение равно 4), так как мы дали ядру указание поместить внеполосные данные вместе с обычными.readПример: дополнительные свойства внеполосных данных
Теперь мы покажем другой столь же простой пример, иллюстрирующий две дополнительные особенности внеполосных данных, о которых мы уже упоминали ранее.
1. TCP посылает уведомление об отправке внеполосных данных (их срочный указатель), даже если поток данных остановлен функциями управления потоком.
2. Принимающий процесс может получить уведомление о том, что отправитель отослал внеполосные данные (с помощью сигнала
или функцииSIGURG) до того, как эти данные фактически прибудут. Если после получения этого уведомления процесс вызывает функциюselect, задавая флагrecv, а внеполосные данные еще не прибыли, то будет возвращена ошибкаMSG_OOB.EWOULDBLOCKВ листинге 24.8 приведена программа отправки.
Листинг 24.8. Программа отправки
//oob/tcpsend05.c1 #include "unp.h"2 int3 main(int argc, char **argv)4 {5 int sockfd, size;6 char buff[16384];7 if (argc != 3)8 err_quit("usage: tcpsend04 <host> <port#>");9 sockfd = Tcp_connect(argv[1], argv[2]);10 size = 32768;11 Setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));12 Write(sockfd, buff, 16384);13 printf("wrote 16384 bytes of normal data\n");14 sleep(5);15 Send(sockfd, "a", 1, MSG_OOB);16 printf("wrote 1 byte of OOB data\n");17 Write(sockfd, buff, 1024);18 printf("wrote 1024 bytes of normal data\n");