是否可以对管道进行读而不是块,而是写块?

Fla*_*ash 5 c unix select posix pipe

man 2 select在“BUGS”下说明以下内容:

在 Linux 下,select() 可能会将套接字文件描述符报告为“已准备好读取”,但后续读取会阻塞。例如,当数据已到达但经检查校验和错误并被丢弃时,可能会发生这种情况。可能存在文件描述符被错误地报告为就绪的其他情况。因此,在不应阻塞的套接字上使用 O_NONBLOCK 可能更安全。

因此,我的read调用不需要阻塞,因此我标记了我的管道文件描述符O_NONBLOCK。但是,我希望write调用阻塞,直到数据写入管道。

是否有可能write向管道写入数据时发生阻塞,但read读取端没有阻塞?例如,fcntl仅在创建管道后才在一端调用是否合法,因为读取端和写入端具有单独的文件描述符?

Mar*_*ian 2

您当然可以在每个writewith之前删除 O_NONBLOCK 标志fcntl,并在完成后将其放回原处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);
}
Run Code Online (Sandbox Code Playgroud)