简单的答案是一直读取,直到
read()
返回
EWOULDBLOCK
(或
EAGAIN
),或者出现错误。
除非你使用的操作系统(或运行时)有错误,否则你所说的简直不可能发生。否则你一定做错了什么。例如,
select()
使用水平触发的I/O。我认为,最可能的情况是你没有完全排空套接字,因此
select()
总是指示你还有一些数据未处理(这在边缘触发事件通知中是不会发生的)。
下面是一个简单的示例,展示了如何持续读取,直到
read()
返回
EWOULDBLOCK
,以避免将描述符留在可读状态(我已经在OS X上编译和测试过了,代码中基本没有错误检查,但你应该能明白意思)。
#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
int n;
fd_set set;
ssize_t bytes;
size_t total_bytes;
char buf[1024];
fd = open("/tmp/fifo", O_RDWR | O_NONBLOCK);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
FD_ZERO(&set);
FD_SET(fd, &set);
for (;;) {
n = select(fd+1, &set, NULL, NULL, NULL);
if (!n)
continue;
if (n == -1) {
perror("select");
return EXIT_FAILURE;
}
if (FD_ISSET(fd, &set)) {
printf("Descriptor %d is ready.\n", fd);
total_bytes = 0;
for (;;) {
bytes = read(fd, buf, sizeof(buf));
if (bytes > 0) {
total_bytes += (size_t)bytes;
} else {
if (errno == EWOULDBLOCK) {
printf("done reading (%lu bytes)\n", total_bytes);
break;
} else {
perror("read");
return EXIT_FAILURE;
}
}
}
}
}
return EXIT_SUCCESS;
}
基本上,水平触发I/O意味着如果有可读内容,您将始终收到通知,即使您之前可能已经收到了通知。相反,边缘触发I/O意味着只有在每次新数据到达时才会收到一次通知,而无论您是否阅读它都没有关系。
select()
是一个水平触发的I/O接口。
希望这能帮到您。祝好运!