Linux 如何在读取函数调用中实现超时?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2917881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implement a timeout in read function call?
提问by domlao
I want to use serial com port for communication and I want to implement a timeout every time I call the read function call.
我想使用串行com端口进行通信,并且每次调用read函数调用时都想实现超时。
int filedesc = open( "dev/ttyS0", O_RDWR );
read( filedesc, buff, len );
EDIT:
编辑:
I'm using Linux OS. How to implement using select function call?
我正在使用 Linux 操作系统。如何使用select函数调用来实现?
采纳答案by Puppe
select() takes 5 parameters, first the highest file descriptor + 1, then a fd_set for read, one for write and one for exceptions. The last paramter is a struct timeval, used for timeout. It return -1 on error, 0 on timeout or the number of file descriptors in the sets that are set.
select() 有 5 个参数,首先是最高的文件描述符 + 1,然后是一个 fd_set 用于读取,一个用于写入,一个用于异常。最后一个参数是一个struct 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 */
}
回答by sth
If you set the socket do operate in non-blocking mode, each call to read will read only the data currently available (if any). So this is effectively equal to an immediate timeout.
如果将套接字设置为在非阻塞模式下运行,则每次调用 read 将只读取当前可用的数据(如果有)。所以这实际上等于立即超时。
You can set non-blocking mode on a socket with a function like this:
您可以使用如下函数在套接字上设置非阻塞模式:
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);
}
(For more information about reading from non-blocking sockets see the read
man page)
(有关从非阻塞套接字读取的更多信息,请参阅read
手册页)
回答by sizzzzlerz
You don't say what the OS is but if you're running under Linux, you could use the select call. It returns if there is something to read on the file descriptor or you can set it up so that it will timeout if there is nothing to read. The return code indicates which.
你没有说操作系统是什么,但如果你在 Linux 下运行,你可以使用 select 调用。如果文件描述符上有要读取的内容,它就会返回,或者您可以设置它,以便在没有要读取的内容时超时。返回码指示哪个。
回答by caf
As an alternative to select()
, for the specific case of a serial port (terminal) you can use tcsetattr()
to put the file descriptor into non-canonical mode, with a read timeout.
作为替代select()
,对于串行端口(终端)的特定情况,您可以使用tcsetattr()
将文件描述符置于非规范模式,读取超时。
To do this, unset the ICANON
flag, and set the VTIME
control character:
为此,请取消设置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);
Note VTIME
is measured in tenths of a second, and that the type used for it is typically an unsigned char
, meaning that the maximum timeout is 25.5 seconds.
注意VTIME
以十分之一秒为单位,用于它的类型通常是 an unsigned char
,这意味着最大超时为 25.5 秒。
回答by rick-rick-rick
The code below uses millisec timeouts per character. I use it in one of my project to read from COM port.
下面的代码使用每个字符的毫秒超时。我在我的一个项目中使用它从 COM 端口读取。
size_t TimeoutRead (int port, void*buf, size_t size, int mlsec_timeout)
{
struct pollfd fd = { .fd = port, .events = POLLIN };
size_t bytesread = 0;
while (poll (&fd, 1, mlsec_timeout) == 1)
{
int chunksize = read (port, buf + bytesread, size);
if (chunksize == -1)
return -1;
bytesread += chunksize;
size -= chunksize;
if (size == 0)
return bytesread;
}
// TODO: IsTimeout = true;
return bytesread;
}