【问题标题】:Reading two consecutive writes from a FIFO using select() and O_NONBLOCK使用 select() 和 O_NONBLOCK 从 FIFO 读取两个连续写入
【发布时间】:2016-04-23 02:44:17
【问题描述】:

我正在尝试编写两个连续的字符串。问题是在阅读器上使用O_NONBLOCK 时,阅读器一直在问候 EAGAIN。

知道为什么在使用 O_NONBLOCK 时它不起作用,select() 不应该处理这个块吗?

reader.c

#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int main() {
    int fd;
    char * myfifo = "/tmp/myfifo";

    mkfifo(myfifo, 0666);
    fd = open(myfifo, O_RDWR | O_NONBLOCK);

    write(fd, "12345678", strlen("12345678"));
    write(fd, "HelloWorld", strlen("HelloWorld"));
    close(fd);

    return 0;
}

writer.c

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>

char buf[BUFSIZ] = { 0 }, buf2[BUFSIZ] = { 0 };
int read1 = 0, read2 = 0;

int main() {
    int fd = 0, a = 0, b = 0 ; 
    char *myfifo= "/tmp/myfifo";

    mkfifo(myfifo, 0666);
    fd_set set;

    if ((fd = open(myfifo, O_RDWR | O_NONBLOCK)) < 0)
        exit(1);

    while (1) {
        FD_ZERO(&set);
        FD_SET(fd, &set);

        if ((select(fd+1, &set, NULL, NULL, NULL)) < 1)
            exit(1);

        if (FD_ISSET(fd, &set)) {
            int total = 0;

            if ((total = read(fd, buf + read1, sizeof(uint32_t) * 2) - read1) <= 0) {
                fprintf(stderr, "%s\n", strerror(errno));
                continue;
            }   
            read1 += total;

            if ((total = read(fd, buf2 + read2, BUFSIZ - read2)) <= 0) {
                fprintf(stderr, "%s\n", strerror(errno));
                continue;
            }   
            read2 += total;

            fprintf(stderr, "%s %d, %d, %s\n", buf, a, b, buf2);
            memset(buf, 0, BUFSIZ);
            memset(buf2, 0, BUFSIZ);
            read1 = read2 = 0;
        }   
    }   

    return 0;
}

【问题讨论】:

  • “open”的 Linux 手册页对在 fifo 上使用 O_RDWR 进行了以下说明:“O_RDWR 打开用于读写。如果将此标志应用于 FIFO,则结果未定义。”跨度>
  • 在 Linux 上没问题,参见 fifo 的手册页:在 Linux 下,打开 FIFO 进行读写将在阻塞和非阻塞模式下都成功。 POSIX 未定义此行为。

标签: c select named-pipes nonblocking fifo


【解决方案1】:

您在循环中调用 fd 上的 read 两次,可能第一个 read 读取可用数据,第二个 read 将失败并返回 EAGAIN。 您应该在执行任何read 之前使用 select 测试准备情况,而不仅仅是第一个。因为 fifo 是流,这意味着您必须维护自己的不同数据片段的边界。

char buf[BUFSIZ];
if (FD_ISSET(fd, &set)) {
    int total = 0;
    int off = 0;
    total = read(fd, buf, sizeof buf);
    if (total <= 0) {
            fprintf(stderr, "%s\n", strerror(errno));
            continue;
    }
    // retrieve the data based on how many bytes you have read
    if (total >= sizeof(uint32_t) * 2) {
        ...
    }
}   

另外,建议用O_RDONLY打开读端,O_WRONLY打开fifo的写端。

【讨论】:

  • 谢谢。据我了解,我应该能够在第一次读取时读取n 字节数,在第二次读取时读取n 量?从您的示例来看,我似乎应该一次读取缓冲区的整个大小?
  • 另外,我相信select() 不会因为O_RDONLY 而因为EOF 而被使用,因此我必须使用O_RDWR
  • @PeteDarrow 但是不能保证您可以在第一次读取时读出 n 个字节,您可能会被读取的更少。正如我所说,流中没有边界,您在一个块中写入的内容不一定会被读取为一个块。
  • 我同意,但是,我认为传递 buf + read1, sizeof(uint32_t) * 2) - read1 应该涵盖需要读取剩余内容的情况,除非我遗漏了什么?
  • 通过使用非阻塞IO,任何时候你读的时候,你应该期望你读的数据量少于你想读的数据量。
猜你喜欢
  • 2014-11-12
  • 2019-03-08
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 2023-03-04
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多