Категории
Самые читаемые
PochitayKnigi » Компьютеры и Интернет » Программное обеспечение » UNIX: разработка сетевых приложений - Уильям Стивенс

UNIX: разработка сетевых приложений - Уильям Стивенс

Читать онлайн UNIX: разработка сетевых приложений - Уильям Стивенс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 181 182 183 184 185 186 187 188 189 ... 263
Перейти на страницу:

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

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

freebsd4 % tcprecv04 6666

read 3 bytes: 123

at OOB mark

read 2 bytes: 45

received EOF

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

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

Теперь мы покажем другой столь же простой пример, иллюстрирующий две дополнительные особенности внеполосных данных, о которых мы уже упоминали ранее.

1. TCP посылает уведомление об отправке внеполосных данных (их срочный указатель), даже если поток данных остановлен функциями управления потоком.

2. Принимающий процесс может получить уведомление о том, что отправитель отослал внеполосные данные (с помощью сигнала SIGURG или функции select) до того, как эти данные фактически прибудут. Если после получения этого уведомления процесс вызывает функцию recv, задавая флаг MSG_OOB, а внеполосные данные еще не прибыли, то будет возвращена ошибка EWOULDBLOCK.

В листинге 24.8 приведена программа отправки.

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

//oob/tcpsend05.c

 1 #include "unp.h"

 2 int

 3 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 datan");

14  sleep(5);

15  Send(sockfd, "a", 1, MSG_OOB);

16  printf("wrote 1 byte of OOB datan");

17  Write(sockfd, buff, 1024);

18  printf("wrote 1024 bytes of normal datan");

19  exit(0);

20 }

9-19 Этот процесс устанавливает размер буфера отправки сокета равным 32 768 байт, записывает 16 384 байт обычных данных, а затем на 5 с переходит в спящее состояние. Чуть ниже мы увидим, что приемник устанавливает размер приемного буфера сокета равным 4096 байт, поэтому данные, отправленные отсылающим TCP, с гарантией заполнят приемный буфер сокета получателя. Затем отправитель посылает один байт внеполосных данных, за которым следуют 1024 байт обычных данных, и, наконец, закрывает соединение.

В листинге 24.9 представлена принимающая программа.

Листинг 24.9. Принимающая программа

//oob/tcprecv05.c

 1 #include "unp.h"

 2 int listenfd, connfd;

 3 void sig_urg(int);

 4 int

 5 main(int argc, char **argv)

 6 {

 7  int size;

 8  if (argc == 2)

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

10  else if (argc == 3)

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

12  else

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

14  size = 4096;

15  Setsockopt(listenfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

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

17  Signal(SIGURG, sig_urg);

18  Fcntl(connfd, F_SETOWN, getpid());

19  for (;;)

20   pause();

21 }

22 void

23 sig_urg(int signo)

24 {

25  int n;

26  char buff[2048];

27  printf("SIGURG receivedn");

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

29  buff[n] = 0; /* завершающий пустой байт */

30  printf("read %d OOB byten", n);

31 }

14-20 Принимающий процесс устанавливает размер приемного буфера сокета приемника равным 4096 байт. Этот размер наследуется присоединенным сокетом после установления соединения. Затем процесс вызывает функцию accept, задает обработчик для сигнала SIGURG и задает владельца сокета. В главном цикле (бесконечном) вызывается функция pause.

22-31 Обработчик сигнала вызывает функцию recv для считывания внеполосных данных.

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

macosx % tcpsend05 freebsd 5555

wrote 16384 bytes of normal data

wrote 1 byte of OOB data

wrote 1024 bytes of normal data

Как и ожидалось, все данные помещаются в буфер отправки сокета отправителя, и программа завершается. Ниже приведен результат работы принимающей программы:

freebsd4 % tcprecv05 5555

SIGURG received

recv error: Resource temporarily unavailable

Сообщение об ошибке, которое выдает наша функция err_sys, соответствует ошибке EAGAIN, которая в FreeBSD аналогична ошибке EWOULDBLOCK. TCP посылает уведомление об отправке внеполосных данных принимающему TCP, который в результате генерирует сигнал SIGURG для принимающего процесса. Но когда вызывается функция recv и задается флаг MSG_OOB, байт с внеполосными данными не может быть прочитан.

Для решения этой проблемы необходимо, чтобы получатель освобождал место в своем приемном буфере, считывая поступившие обычные данные. В результате TCP объявит для отправителя окно ненулевого размера, что в конечном счете позволит отправителю передать байт, содержащий внеполосные данные.

ПРИМЕЧАНИЕ

В реализациях, происходящих от Беркли [128, с. 1016-1017], можно отметить две близких проблемы. Во-первых, даже если приемный буфер сокета заполнен, ядро всегда принимает от процесса внеполосные данные для отправки собеседнику. Во-вторых, когда отправитель посылает байт с внеполосными данными, немедленно посылается сегмент TCP, содержащий срочное уведомление. Все обычные проверки вывода TCP (алгоритм Нагла, предотвращение синдрома «глупого окна») при этом блокируются.

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

Нашим очередным примером мы иллюстрируем тот факт, что для данного соединения TCP существует всего одна отметка внеполосных данных, и если новые внеполосные данные прибудут прежде, чем принимающий процесс начнет считывать пришедшие ранее внеполосные данные, то предыдущая отметка будет утеряна.

В листинге 24.10 показана посылающая программа, аналогичная программе, приведенной в листинге 24.6. Отличие заключается в том, что сейчас мы добавили еще одну функцию send для отправки внеполосных данных и еще одну функцию write для записи обычных данных.

Листинг 24.10. Отправка двух байтов внеполосных данных друг за другом

//oob/tcpsend06.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 datan");

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

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

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

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

15  Send(sockfd,. "6", 1, MSG_OOB);

16  printf("wrote 1 byte of OOB datan");

17  Write(sockfd, "7", 1);

18  printf("wrote 1 byte of normal datan");

19  exit(0);

20 }

В данном случае отправка данных происходит без пауз, что позволяет быстро переслать данные собеседнику.

Принимающая программа идентична программе, приведенной в листинге 24.7, где вызывается функция sleep, которая после установления соединения переводит получателя в спящее состояние на 5 с, чтобы позволить данным прибыть на принимающий TCP. Ниже приводится результат выполнения этой программы:

freebsd4 % tcprecv06 5555

read 5 bytes: 12345

at OOB mark

read 2 bytes: 67

received EOF

Прибытие второго байта внеполосных данных (6) изменяет отметку, которая ассоциировалась с первым прибывшим байтом внеполосных данных (4). Как мы сказали, для конкретного соединения TCP допускается только одна отметка внеполосных данных.

24.4. Резюме по теме внеполосных данных TCP

Все приведенные до сих пор примеры, иллюстрирующие использование внеполосных данных, были весьма тривиальны. К сожалению, когда мы начинаем учитывать возможные проблемы, связанные с согласованием во времени при пересылке внеполосных данных, ситуация заметно усложняется. В первую очередь, нужно осознать, что концепция внеполосных данных подразумевает передачу получателю трех различных фрагментов информации:

1 ... 181 182 183 184 185 186 187 188 189 ... 263
Перейти на страницу:
Тут вы можете бесплатно читать книгу UNIX: разработка сетевых приложений - Уильям Стивенс.
Комментарии