Простой пример использования функции select

Простой пример использования функции select

Теперь мы переделаем код нашего получателя внеполосных данных и вместо сигнала SIGURG будем использовать функцию select. В листинге 24.3 показана принимающая программа.

Листинг 24.3. Принимающая программа, в которой (ошибочно) используется функция select для уведомления о получении внеполосных данных

//oob/tcprecv02.c

 1 #include "unp.h"

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int listenfd, connfd, n;

 6  char buff[100];

 7  fd_set rset, xset;

 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: tcprecv02 [ <host> ] <port#>");

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

15  FD_ZERO(&rset);

16  FD_ZERO(&xset);

17  for (;;) {

18   FD_SET(connfd, &rset);

19   FD_SET(connfd, &xset);

20   Select(connfd + 1, &rset, NULL, &xset, NULL);

21   if (FD_ISSET(connfd, &xset)) {

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

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

24    printf("read OOB byte: %s ", n, buff);

25   }

26   if (FD_ISSET(connfd, &rset)) {

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

28     printf("received EOF ");

29     exit(0);

30    }

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

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

33   }

34  }

35 }

15-20 Процесс вызывает функцию select, которая ожидает получения либо обычных данных (набор дескрипторов для чтения, rset), либо внеполосных (набор дескрипторов для обработки исключений, xset). В обоих случаях полученные данные выводятся.

Если мы запустим эту программу, а затем — программу для отправки, которая приведена в листинге 24.1, то столкнемся со следующей ошибкой:

freebsd4 % tcprecv02 9999

read 3 bytes: 123

read 1 OOB byte: 4

recv error: Invalid argument

Проблема заключается в том, что функция select будет сообщать об исключительной ситуации, пока процесс не считает данные, находящиеся за отметкой внеполосных данных (то есть после них [128, с. 530-531]). Мы не можем считывать внеполосные данные больше одного раза, так как после первого же их считывания ядро очищает буфер, содержащий один байт внеполосных данных. Когда мы вызываем функцию recv, устанавливая флаг MSG_OOB во второй раз, она возвращает ошибку EINVAL.

Чтобы решить эту проблему, нужно вызывать функцию select для проверки на наличие исключительной ситуации только после того, как будут приняты все обычные данные. В листинге 24.4 показана модифицированная версия принимающей программы из листинга 24.3. В этой версии описанный сценарий обрабатывается корректно.

Листинг 24.4. Модификация программы, приведенной в листинге 24.3. Функция select применяется для проверки исключительной ситуации корректным образом

//oob/tcprecv03.c

 1 #include "unp.h"

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int listenfd, connfd, n, justreadoob = 0;

 6  char buff[100];

 7  fd_set rset, xset;

 8  if (argc == 2)

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

10  else if (argc == 3)

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

12  else

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

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

15  FD_ZERO(&rset);

16  FD_ZERO(&xset);

17  for (;;) {

18   FD_SET(connfd, &rset);

19   if (justreadoob == 0)

20    FD_SET(connfd, &xset);

21   Select(connfd + 1, &rset, NULL, &xset, NULL);

22   if (FD_ISSET(connfd, &xset)) {

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

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

25    printf("read %d OOB byte: %s ", 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 ");

32     exit(0);

33    }

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

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

36    justreadoob = 0;

37   }

38  }

39 }

5 Мы объявляем новую переменную с именем justreadoob, которая указывает, какие данные мы считываем — внеполосные или обычные. Этот флаг определяет, нужно ли вызывать функцию select для проверки на наличие исключительной ситуации.

26-27 Когда мы устанавливаем флаг justreadoob, мы также должны выключить бит соответствующего дескриптора в наборе для проверки исключительных ситуаций.

Теперь программа работает так, как мы ожидали.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Пример: очереди сообщений Posix и функция select

Из книги UNIX: взаимодействие процессов автора Стивенс Уильям Ричард

Пример: очереди сообщений Posix и функция select Дескриптор очереди сообщений (переменная типа mqd_t) не является «обычным» дескриптором и не может использоваться с функциями select и poll (глава 6 [24]). Тем не менее их можно использовать вместе с каналом и функцией mq_notify. (Аналогичный


19.5.1. Простой пример

Из книги Программирование на языке Ruby [Идеология языка, теория и практика применения] автора Фултон Хэл


Пример оператора Select Case

Из книги VBA для чайников автора Каммингс Стив

Пример оператора Select Case Здесь явно не помешает пример, показывающий, как в действительности может выглядеть структура Select Case. Select Case objRol l OfFi l m.Type Case "Слайдовая" intСлайдовые = intСлайдовые + 1 Case "Цветная негативная" intЦветныеНегативные =


Простой пример функции io_read()

Из книги Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform автора Кёртен Роб

Простой пример функции io_read() Чтобы проиллюстрировать, как ваш администратор ресурса мог бы возвращать клиенту данные, рассмотрим простейший администратор ресурса, который всегда возвращает одну и ту же строковую константу «Здравствуй, мир! ». Даже в таком простом случае


Простой пример функции io_write()

Из книги Искусство программирования на языке сценариев командной оболочки автора Купер Мендель

Простой пример функции io_write() Это был простой пример функции io_read(); давайте теперь перейдем к функции io_write(). Основной камень преткновения, связанный с io_write(), — получить доступ к данным. Поскольку библиотека администратора ресурсов считывает лишь незначительную часть


Простой пример функции io_devctl()

Из книги CSS3 для веб-дизайнеров автора Сидерхолм Дэн

Простой пример функции io_devctl() Клиентский вызов devctl() формально определен так:#include <sys/types.h>#include <unistd.h>#include <devctl.h>int devctl(int fd, int dcmd, void *dev_data_ptr, size_t nbytes, int *dev_info_ptr);Прежде чем рассматривать эту функцию с позиций администратора ресурсов, надо сначала понять, что это за


Пример 10-27. Простой пример сравнения строк

Из книги Недокументированные и малоизвестные возможности Windows XP автора Клименко Роман Александрович

Пример 10-27. Простой пример сравнения строк #!/bin/bash# match-string.sh: простое сравнение строкmatch_string (){ MATCH=0 NOMATCH=90 PARAMS=2 # Функция требует два входных аргумента. BAD_PARAMS=91 [ $# -eq $PARAMS ] || return $BAD_PARAMS case "$1" in "$2") return $MATCH;; * ) return $NOMATCH;; esac}a=oneb=twoc=threed=twomatch_string $a # неверное число


Простой пример

Из книги Linux и UNIX: программирование в shell. Руководство разработчика. автора Тейнсли Дэвид

Простой пример Начнем с простого примера: наложим переход на изменение фона ссылки. Когда пользователь будет наводить на ссылку, цвет ее фона будет меняться, и мы применим переход, чтобы сделать это изменение плавным. Такого эффекта раньше можно было добиться


Простой пример

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

Простой пример Конечно, приведенный выше пример довольно сложен — ведь он написан на машинном языке и в шестнадцатиричном виде. Но его можно упростить, ведь отладчик в Windows XP поддерживает как ASCII-символы, так и язык «Ассемблера».Вот упрощением мы сейчас и займемся.


20.1.1. Простой способ использования команды shift

Из книги автора

20.1.1. Простой способ использования команды shift Для обработки каждого передаваемого аргумента достаточно воспользоваться командой shift. Ниже приводится соответствующий сценарий:$ pg opt2#!/bin/sh# oPt21оор=0while [ $# -ne 0 ] # цикл выполняется до тех пор, пока остаются аргументы doecho $1shift


Глава 6 Мультиплексирование ввода-вывода: функции select и poll

Из книги автора

Глава 6 Мультиплексирование ввода-вывода: функции select и poll 6.1. Введение В разделе 5.12 мы видели, что наш TCP-клиент обрабатывает два входных потока одновременно: стандартный поток ввода и сокет TCP. Проблема, с которой мы столкнулись, состояла в том, что пока клиент был


Максимальное число дескрипторов для функции select

Из книги автора

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


Тайм-аут для функции recvfrom (функция select)

Из книги автора

Тайм-аут для функции recvfrom (функция select) Мы демонстрируем вторую технологию для установки тайм-аута (использование функции select) в листинге 14.3. Здесь показана наша функция readable_timeo, которая ждет, когда дескриптор станет готов для чтения, но не более заданного числа


Простой пример использования сигнала SIGURG

Из книги автора

Простой пример использования сигнала SIGURG Теперь мы рассмотрим тривиальный пример отправки и получения внеполосных данных. В листинге 24.1[1] показана программа отправки этих данных.Листинг 24.1. Простая программа отправки внеполосных данных//oob/tcpsend01.c 1 #include "unp.h" 2 int 3 main(int


Коллизии при вызове функции select

Из книги автора

Коллизии при вызове функции select Рассматривая данный пример в 4.4BSD, мы можем исследовать еще одну проблему, которая встречается довольно редко и поэтому часто остается непонятой до конца. В разделе 16.13 [128] говорится о коллизиях (collisions), возникающих при вызове функции select