编辑
我的主要目标是在select()
通知传入数据后刷新可读的文件描述符。正如Basile Starynkevitch所指出的,我现在只需要为read()
提供一个足够大的缓冲区就可以实现这个目标。这就是为什么我把这个答案标记为已接受。
标题中的问题还没有得到回答:如何从这样的文件描述符中获得我可以读取的最小字节数:
min_size = fd_get_chunksize(file_descriptor);
其可能返回1、4、8或其他值。
原始问题
我有几个以不同方式创建的文件描述符。例如,使用timerfd_create()
,并将其配置为每秒发射一次。
当select()
在某个FD上发出通信信号时,我想刷新它。对于用timerfd_create()
创建的FD,我必须读取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 %ldn", count, data);
}
}
当data
被声明为char
,因此sizeof(data)为1时,count
总是0
,并且我的文件描述符永远不会被刷新。
如果我有多个文件描述符要刷新(可能创建方式不同),我必须知道每个文件描述符的字节数,我必须读取以刷新它
有没有办法为现有的FD获得这么多字节?
有没有其他方法可以刷新我用timerfd_create()
创建的文件描述符?(我在没有read()的情况下读取了Empty或"flush"文件描述符?但这并没有给我答案。)事实上,我不想阅读内容,只是想让它再次为select()
做好准备。
仔细阅读timerfd_create(2)
在计时器文件描述符上操作
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;
对于普通的文件描述符,您知道应该读取多少字节。也许它是一个带有小固定长度消息的管道或套接字(或鼠标设备)。但总的来说,您最好读取足够大的缓冲区(通常,几KB,最高可达一兆字节;也许64KB=65536字节是一个不错的折衷方案)。注意:(2)成功返回一个字节计数,因此可以进行部分读取。如果某些字节保持立即可读,则下一次轮询(2)(或几乎过时的select
)将立即成功。
另请参阅管道(7)中关于管道容量的段落
您也可以考虑旧的FIONBIO
ioctl(2),但我不建议使用它(它不是很可移植,语义定义不太好:它可能会提供可读取的字节数)。看看这个。
避免读取(2)非常小的缓冲区(几个字节)。特别是,read
一次处理一个字节的性能总是非常糟糕。
顺便说一句,一些硬件块设备可能想要以某个块大小的倍数读取(2),该块大小通常适合几千字节(例如一页或两页)。YMMV。
也许异步IO(参见aio(7))可能是有用的。