读取描述符的非阻塞调用

时间:2011-04-11 01:57:45

标签: c unix

我有一个fd描述符,我可以通过调用read(fd, buffer,...)来读取它。现在,我想在实际拨打电话之前检查是否有任何内容需要阅读,因为呼叫是阻塞的。我该怎么做?

7 个答案:

答案 0 :(得分:54)

int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

上面的代码片段将为非阻塞访问配置此类描述符。如果在调用read时数据不可用,则系统调用将失败,返回值为-1,并且errno设置为EAGAIN。有关详细信息,请参阅fnctl手册页。

或者,您可以使用select和可配置的超时来检查和/或等待指定的时间间隔以获取更多数据。这种方法可能就是你想要的,效率更高。

答案 1 :(得分:12)

使用selectpoll来查询文件描述符是否有可供读取的数据:

fd_set fds;
FD_ZERO(&fds);
FD_SET(&fds, fd);
if (select(fd+1, &fds, 0, 0)==1) /* there is data available */

答案 2 :(得分:6)

好的,STDIN可以按照您的意愿在非阻塞模式下读取。您首先需要将套接字设置为非阻塞模式,如

int flags = fcntl(fd, F_GETFL, 0);
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK))
    ;// some kind of fail

当您准备好从缓冲区读取数据时,您可以按如下方式尝试读取:

int count;
char buffer[1024];
count = read(fd, buffer, 1024);
if(count < 0 && errno == EAGAIN) {
    // If this condition passes, there is no data to be read
}
else if(count >= 0) {
    // Otherwise, you're good to go and buffer should contain "count" bytes.
}
else {
    // Some other error occurred during read.
}

请注意,1024的缓冲区大小当然是任意的。

答案 3 :(得分:3)

我认为您应该使用selectpoll函数来检查是否有从描述符中读取的内容。

答案 4 :(得分:1)

根据您正在做的事情,您可以将问题彻底解决,并使用select告诉您文件描述符何时可以阅读。

答案 5 :(得分:1)

查看您用于特定编程目的的API或系统/工具。 (描述符/文件描述符在Linux编程中有很多用途,如套接字编程,文件操作,shared_memory等)。

例如,有一次我使用了inotify(用于监视文件系统事件)。此API使您能够从第一点创建非阻塞文件,并且无需使用fcntl或此类API来修改创建的文件描述符。

您可能会使用的其他工具或API具有此类功能,您可以在启动或此类步骤中设置此类选项(请先检查)。

但通常是使用fcntl是答案,知道inotify本身也使用fcntl本身可能会很有趣。 (参考Linux的手册页)

select()可以为您提供与在文件描述符上操作相同的功能,用于监视具有指定限制时间的事件,但请记住,select的主要用途是用于监视多个文件描述符。

答案 6 :(得分:1)

use poll for timeout:

struct pollfd p;
            int n;
            while ((n = poll(&p, 1, iTo)) < 0) 
              {
               if (errno == EAGAIN || errno == EINTR)
                   continue;
            }

            if (!n) {
                 errno = ETIMEDOUT;
                   }

        while ((len = read(Fd, anyBuff, sizeof(anyenter code hereBuff))) < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;

        }