man 2 select
在BUGS下声明以下内容:
在Linux下,select()可以报告套接字文件描述符为"准备好了 尽管如此,阅读",然后是后续的读取块。这可以 例如,当数据到达但检查有错误时会发生 校验和并被丢弃。可能还有其他情况 文件描述符被虚假报告为就绪。因此它可能更安全 在不应阻塞的套接字上使用O_NONBLOCK。
因此,我的read
调用不需要阻塞,因此我已经标记了我的管道文件描述符O_NONBLOCK
。但是,我希望write
调用阻塞,直到数据写入管道。
将数据写入管道时是否可能阻塞write
,但是read
是否阻止了读取端?例如,仅在创建管道之后在一端调用fcntl
是否合法,因为读取和写入结束具有单独的文件描述符?
答案 0 :(得分:1)
您肯定可以在write
的每个fcntl
之前删除O_NONBLOCK标志,并在write
完成后将其恢复。但是,最好始终保持套接字不阻塞,并将write
置于循环中直到完成。为了不使CPU过载,请选择一个将阻塞进程的选择,直到套接字准备好写入为止。
因此,编写代码如下:
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);
}