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");
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 [
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 received\n");
28 n = Recv(connfd, buff, sizeof(buff) - 1, MSG_OOB);
29 buff[n] = 0; /* завершающий пустой байт */
30 printf("read %d OOB byte\n", 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 объявит для отправителя окно ненулевого размера, что в конечном счете позволит отправителю передать байт, содержащий внеполосные данные.