man 2 select
在“BUGS”下说明以下内容:
在 Linux 下,select() 可能会将套接字文件描述符报告为“ready for 读”,而随后的读块。这可以用于 示例发生在数据已到达但经检查有错误时 校验和并被丢弃。可能还有其他情况,其中 文件描述符被错误地报告为就绪。因此可能更安全 在不应阻塞的套接字上使用 O_NONBLOCK。
因此,我的
read
调用不需要阻塞,因此我标记了我的管道文件描述符 O_NONBLOCK
。但是,我希望 write
调用阻塞,直到数据写入管道。
是否可以在向管道写入数据时让
write
阻塞,但让read
不阻塞读取端?例如,仅在创建管道后才在一端调用 fcntl
是否合法,因为读端和写端具有单独的文件描述符?
您当然可以在每个
write
之前使用 fcntl
删除 O_NONBLOCK 标志,并在 write
完成后将其放回去。但是,最好始终保持套接字非阻塞并将 write
放入循环中直到完成。为了不使 CPU 过载,请放置一个 select 来阻塞进程,直到套接字准备好写入为止。
所以,编写代码将如下所示:
int blockingWriteOnNonBlockingFd(int fd, char *buf, int size) {
fd_set wset, w;
int n, r;
FD_ZERO(&wset);
FD_SET(fd, &wset);
n = 0;
while (n < size) {
w = wset;
select(fd+1, NULL, &w, NULL, NULL);
r = write(fd, buf+n, size-n);
if (r <= 0) {
if (r<0 && (errno == EWOULDBLOCK || errno == EAGAIN)) r = 0;
else { /* broken connection */ break; }
}
n += r;
}
return(n);
}