管道上的非阻塞读取 [英] Non-blocking read on pipe
问题描述
可以在管道上执行非阻塞I/O吗? fcntl无法设置O_NONBLOCK. Linux编程接口的第918页包括一个表从管道或FIFO(p)读取n个字节的语义".下表列出了管道和FIFO的行为,其中标题为O_NONBLOCK的列已启用?这意味着您可以在管道上设置O_NONBLOCK标志.这样对吗?以下代码无法设置该标志,但是fcntl(2)不会报告错误.
Can one do non-blocking I/O on a pipe? fcntl fails to set O_NONBLOCK. Page 918 of The Linux Programming Interface includes a table 'Semantics of reading n bytes from pipe or FIFO (p)'. This table lists the behaviour of pipes and FIFO's with one column titled O_NONBLOCK enabled? This would imply that you can set the O_NONBLOCK flag on a pipe. Is this correct? The following code fails to set the flag, fcntl(2) does not report an error though.
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define SLEEP 1
int
main(int argc, char *argv[]) {
pid_t childPid;
int pfd[2];
int nread, flags;
int c = 'a';
setbuf(stdout, NULL);
if (pipe(pfd) == -1) {
printf("error: pipe");
exit(EXIT_FAILURE);
}
switch (childPid = fork()) {
case -1:
printf("error: fork");
exit(EXIT_FAILURE);
case 0: /* child */
if (close(pfd[0]) == -1) {
printf("child: close pfd read");
exit(EXIT_FAILURE);
}
sleep(SLEEP);
_exit(EXIT_SUCCESS);
default:
break;
/* parent falls through */
}
if (close(pfd[1]) == -1) {
printf("parent: close pipe write");
exit(EXIT_FAILURE);
}
flags = fcntl(pfd[0], F_GETFD);
flags |= O_NONBLOCK;
if (fcntl(pfd[0], F_SETFD, flags))
perror("fcntl");
/* verify flags set correctly */
flags = fcntl(pfd[0], F_GETFD);
if (!(flags & O_NONBLOCK)) {
printf("failed to set O_NONBLOCK\n");
exit(EXIT_FAILURE);
}
wait(NULL);
exit(EXIT_SUCCESS);
}
推荐答案
管道和O_NONBLOCK没有什么特别的.下面的示例按预期方式工作.我没有检查每个调用的每个检索,以使示例更具可读性.真实的应用程序必须进行检查.
There is nothing special to pipe and O_NONBLOCK. The following example work as expected. I did not check every retval from every call to make the example a bit more readable. A real world application must do the checks.
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
int main()
{
int fds[2];
pid_t pid;
char buf[100];
pipe(fds);
pid = fork();
if ( pid )
{
while (1 )
{
memcpy( buf, "abcdefghi\0",10);
write( fds[1], buf, 10);
sleep(2);
}
}
else
{
int retval = fcntl( fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);
printf("Ret from fcntl: %d\n", retval);
while (1)
{
ssize_t r=read( fds[0], buf, 10 );
printf("read: %d\n", r);
if ( r > 0 )
{
printf("Buffer: %s\n", buf);
}
else
{
printf("Read nothing\n");
perror("Error was");
sleep(1);
}
}
}
}
在编写示例之后,我检查了您的代码并发现:
After writing my example I inspect your code and found:
flags = fcntl(pfd[0], F_GETFD);
flags |= O_NONBLOCK;
if (fcntl(pfd[0], F_SETFD, flags))
请同时将F_SETFD
更改为F_SETFL
并进行get操作.您不会更改file descriptor flags
,但会更改file descriptor status flags
:-)
Please change F_SETFD
to F_SETFL
and also for the get operation. You would not change the file descriptor flags
but the file descriptor status flags
:-)
来自man 3 fcntl
:
文件描述符标志 以下命令操纵与文件关联的标志 描述符.当前,仅定义了一个这样的标志:FD_CLOEXEC, 执行时关闭标志.如果FD_CLOEXEC位为0,则文件描述符 将在execve(2)上保持打开状态,否则将关闭.
File descriptor flags The following commands manipulate the flags associated with a file descriptor. Currently, only one such flag is defined: FD_CLOEXEC, the close-on-exec flag. If the FD_CLOEXEC bit is 0, the file descriptor will remain open across an execve(2), otherwise it will be closed.
文件状态标志 每个打开的文件描述都有某些关联的状态标志,即 由open(2)归一化,并可能由fcntl()修改.重复的文件 描述符(由dup(2),fcntl(F_DUPFD),fork(2)等制成)指 相同的打开文件描述,因此共享相同的文件状态 标志.
File status flags Each open file description has certain associated status flags, ini‐ tialized by open(2) and possibly modified by fcntl(). Duplicated file descriptors (made with dup(2), fcntl(F_DUPFD), fork(2), etc.) refer to the same open file description, and thus share the same file status flags.
F_SETFL(int) 将文件状态标志设置为arg指定的值.文件 访问模式(O_RDONLY,O_WRONLY,O_RDWR)和文件创建标志 arg中的(即O_CREAT,O_EXCL,O_NOCTTY,O_TRUNC)被忽略. 在Linux上,此命令只能更改O_APPEND,O_ASYNC, O_DIRECT,O_NOATIME和 O_NONBLOCK 标志.这不可能 更改O_DSYNC和O_SYNC标志;参见下面的错误".
F_SETFL (int) Set the file status flags to the value specified by arg. File access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored. On Linux this command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags. It is not possible to change the O_DSYNC and O_SYNC flags; see BUGS, below.
这篇关于管道上的非阻塞读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!