Как реализовать тайм-аут при вызове функции чтения? - PullRequest
46 голосов
/ 27 мая 2010

Я хочу использовать последовательный COM-порт для связи, и я хочу реализовать таймаут каждый раз, когда я вызываю вызов функции чтения.

int filedesc = open( "dev/ttyS0", O_RDWR );

read( filedesc, buff, len );

EDIT:

Я использую ОС Linux. Как реализовать, используя вызов функции select?

Ответы [ 5 ]

76 голосов
/ 27 мая 2010

выберите () принимает 5 параметров, сначала самый высокий дескриптор файла + 1, затем fd_set для чтения, один для записи и один для исключений. Последний параметр - это структура timeval, используемая для тайм-аута. Возвращает -1 при ошибке, 0 по таймауту или количество дескрипторов файлов в установленных наборах.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>

int main(void)
{
  fd_set set;
  struct timeval timeout;
  int rv;
  char buff[100];
  int len = 100;
  int filedesc = open( "dev/ttyS0", O_RDWR );

  FD_ZERO(&set); /* clear the set */
  FD_SET(filedesc, &set); /* add our file descriptor to the set */

  timeout.tv_sec = 0;
  timeout.tv_usec = 10000;

  rv = select(filedesc + 1, &set, NULL, NULL, &timeout);
  if(rv == -1)
    perror("select"); /* an error accured */
  else if(rv == 0)
    printf("timeout"); /* a timeout occured */
  else
    read( filedesc, buff, len ); /* there was data to read */
}
39 голосов
/ 27 мая 2010

В качестве альтернативы select() для конкретного случая последовательного порта (терминала) вы можете использовать tcsetattr(), чтобы перевести файловый дескриптор в неканонический режим с таймаутом чтения.

Для этого снимите флажок ICANON и установите управляющий символ VTIME:

struct termios termios;

tcgetattr(filedesc, &termios);
termios.c_lflag &= ~ICANON; /* Set non-canonical mode */
termios.c_cc[VTIME] = 100; /* Set timeout of 10.0 seconds */
tcsetattr(filedesc, TCSANOW, &termios);

Примечание VTIME измеряется в десятых долях секунды, и тип, используемый для него, обычно равен unsigned char, что означает, что максимальное время ожидания составляет 25,5 секунд.

8 голосов
/ 27 мая 2010

Если вы установили, что сокет работает в неблокирующем режиме, каждый вызов read будет читать только те данные, которые доступны в данный момент (если есть). Так что это фактически равно немедленному таймауту.

Вы можете установить неблокирующий режим для сокета с помощью функции, подобной этой:

int setnonblock(int sock) {
   int flags;
   flags = fcntl(sock, F_GETFL, 0);
   if (-1 == flags)
      return -1;
   return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}

(Подробнее о чтении из неблокирующих сокетов см. Справочную страницу read)

4 голосов
/ 27 мая 2010

Вы не говорите, что это за ОС, но если вы работаете в Linux, вы можете использовать вызов select. Он возвращает, если есть что прочитать в дескрипторе файла, или вы можете настроить его так, чтобы он истекал, если нечего читать. Код возврата указывает, какой.

0 голосов
/ 22 октября 2015

Linux считают два типа устройства. «Медленный» (например, сеть) и «быстрый» (например, диск). Неблокирующий режим предназначен для «медленного» устройства, а не для «быстрого». Блокируйте устройства как «быстрые», поэтому команда select / poll всегда сообщает, что они готовы к вводу / выводу. Для некоторых флеш-устройств это ложь, и я видел несколько вызовов ввода-вывода, которые используют несколько секунд для нескольких байтов, даже если select / poll говорит, что устройство готово. Тем не менее, даже для медленного устройства, нет никакой сильной гарантии на саму задержку чтения; Если вы предоставляете достаточно большой буфер и данные доступны (вы использовали select или poll, чтобы убедиться в этом), сам вызов read может использовать значительное количество времени (сотни мс в сети).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...