如何从文件描述符中获取最小字节数到 read()?

how to get the minimum amount of bytes to read() from a file descriptor?

编辑

我的主要目标是在 select() 通知传入数据后刷新可读文件描述符。正如 Basile Starynkevitch 所指出的那样,我现在只需为 read() 提供足够大的缓冲区就可以实现这个目标。这就是我将此答案标记为已接受的原因。

标题中的问题尚未得到解答:如何获得我可以从文件描述符中读取的最小字节数,如下所示:

min_size = fd_get_chunksize(file_descriptor);

可能 return 1、4、8 或其他。

原题

我有几个以不同方式创建的文件描述符。例如。使用 timerfd_create() 并将其配置为每秒触发一次。

select() 在某个 FD 上发出流量信号时,我想刷新它。对于使用 timerfd_create() 创建的那些,我必须至少读取 8 字节:

if(select(fd + 1, &l_fdsRd, NULL, NULL, &l_timeOut)) {
    unsigned long long data;
    int count;
    while((count = read (fd, &data, sizeof(data))) > 0) {
        printf("%d %ld\n", count, data);
    }
}

data 被声明为 char 并且因此 sizeof(data) 为 1 时,count 总是 0 并且我的文件描述符永远不会被刷新。

如果我有多个文件描述符要刷新(可能创建不同),我必须知道我必须读取以刷新它的每个文件描述符的字节数。

有没有办法为现有的 FD 获取这个字节数?

还有其他方法可以刷新我用 timerfd_create() 创建的文件描述符吗? (我读了 Empty or "flush" a file descriptor without read()? 但这没有给我任何答案..) 其实我不想看内容,只是想为select()再做准备。

仔细阅读timerfd_create(2)

Operating on a timer file descriptor

  The file descriptor returned by timerfd_create() supports the
   following operations:

  read(2)
          If the timer has already expired one or more times since its
          settings were last modified using timerfd_settime(), or since
          the last successful read(2), then the buffer given to read(2)
          returns an unsigned 8-byte integer (uint64_t) containing the
          number of expirations that have occurred.  (The returned value
          is in host byte order—that is, the native byte order for
          integers on the host machine.)

         If no timer expirations have occurred at the time of the
          read(2), then the call either blocks until the next timer
          expiration, or fails with the error EAGAIN if the file
          descriptor has been made nonblocking (via the use of the
          fcntl(2) F_SETFL operation to set the O_NONBLOCK flag).

         A read(2) will fail with the error EINVAL if the size of the
          supplied buffer is less than 8 bytes.

  poll(2), select(2) (and similar)
          The file descriptor is readable (the select(2) readfds
          argument; the poll(2) POLLIN flag) if one or more timer
          expirations have occurred.

所以当文件描述符可读时,真的应该读取一个无符号的 8 字节整数。请注意,您不能只读取一个字节(提到 EINVAL 错误)

因此声明

uint64_t data;

对于普通的文件描述符,知道你应该读取多少字节。也许它是带有 small 固定长度消息的管道或套接字(或鼠标设备)。但总的来说,你会更好 read a large enough buffer (typically, several kilobytes, up to a megabyte; perhaps 64Kbytes = 65536 bytes could be a not-too-bad tradeoff). Notice that read(2) 成功返回字节数,因此可以部分读取。如果一些字节保持立即可读,下一个 poll(2)(或几乎过时的 select)将立即成功。

另请参阅 pipe(7)

中有关 管道容量 的段落

您也可以考虑旧的 FIONBIO ioctl(2) but I don't recommend using it (it is not very portable, with a not very well defined semantics : it might give the number of available bytes to read). See this.

避免read(2)-ing 非常小的缓冲区(几个字节)。特别是,read-ing 一次一个字节总是提供深渊性能。

顺便说一句,一些硬件块设备可能希望 read(2) 某些块大小的倍数,通常适合几千字节(例如一两页)。 YMMV.

也许异步 IO(参见 aio(7))可能有用。