管道上的非阻塞读取 [英] Non-blocking read on pipe

查看:136
本文介绍了管道上的非阻塞读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可以在管道上执行非阻塞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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆