简体   繁体   English

管道上的非阻塞读取

[英]Non-blocking read on pipe

Can one do non-blocking I/O on a pipe?可以在管道上进行非阻塞 I/O 吗? fcntl fails to set O_NONBLOCK. fcntl 未能设置 O_NONBLOCK。 Page 918 of The Linux Programming Interface includes a table 'Semantics of reading n bytes from pipe or FIFO (p)'. Linux 编程接口的第 918 页包含一个表“从管道或 FIFO (p) 读取 n 字节的语义”。 This table lists the behaviour of pipes and FIFO's with one column titled O_NONBLOCK enabled?下表列出了管道和 FIFO 的行为,其中一列标题为启用了 O_NONBLOCK? This would imply that you can set the O_NONBLOCK flag on a pipe.这意味着您可以在管道上设置 O_NONBLOCK 标志。 Is this correct?这个对吗? The following code fails to set the flag, fcntl(2) does not report an error though.以下代码未能设置标志,但 fcntl(2) 不报告错误。

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>

int main()
{
    int fds[2];
    pid_t pid;
    char wr_buf[100];
    char rd_buf[100];

    pipe(fds);

    pid = fork();

    if ( pid )
    {
        while (1 )
        {
            memcpy( wr_buf, "abcdefghi\0",10);
            write( fds[1], wr_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], rd_buf, 10 );
            printf("read: %d\n", r);

            if ( r > 0 )
            {
                printf("Buffer: %s\n", rd_buf);
            }
            else
            {
                printf("Read nothing\n");
                perror("Error was");
                sleep(1);
            }
        }
    }
}

There is nothing special to pipe and O_NONBLOCK. pipe 和 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.我没有检查每次调用的每个 retval 以使示例更具可读性。 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))

Please change F_SETFD to F_SETFL and also for the get operation.请将F_SETFD更改为F_SETFL以及获取操作。 You would not change the file descriptor flags but the file status flags :-)您不会更改file descriptor flags ,而是更改file status flags :-)

From man 3 fcntl :来自man 3 fcntl

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.目前,只定义了一个这样的标志:FD_CLOEXEC,close-on-exec 标志。 If the FD_CLOEXEC bit is 0, the file descriptor will remain open across an execve(2), otherwise it will be closed.如果 FD_CLOEXEC 位为 0,则文件描述符将在 execve(2) 中保持打开状态,否则将关闭。

File status flags Each open file description has certain associated status flags, ini‐ tialized by open(2) and possibly modified by fcntl().文件状态标志每个打开的文件描述都有某些相关的状态标志,由 open(2) 初始化,并可能由 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.重复的文件描述符(使用 dup(2)、fcntl(F_DUPFD)、fork(2) 等)引用相同的打开文件描述,因此共享相同的文件状态标志。

F_SETFL (int) Set the file status flags to the value specified by arg. F_SETFL (int) 将文件状态标志设置为 arg 指定的值。 File access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (ie, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored. arg 中的文件访问模式(O_RDONLY、O_WRONLY、O_RDWR)和文件创建标志(即 O_CREAT、O_EXCL、O_NOCTTY、O_TRUNC)被忽略。 On Linux this command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.在 Linux 上,此命令只能更改 O_APPEND、O_ASYNC、O_DIRECT、O_NOATIME 和O_NONBLOCK标志。 It is not possible to change the O_DSYNC and O_SYNC flags;无法更改 O_DSYNC 和 O_SYNC 标志; see BUGS, below.请参阅下面的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM