c - 使用 select() 和 O_NONBLOCK 从 FIFO 读取两个连续写入

标签 c select named-pipes nonblocking fifo

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

有什么想法为什么它在使用 O_NONBLOCK 时不起作用,select() 不应该处理该 block 吗?

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;
}

最佳答案

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

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打开fifo的读取端,使用O_WRONLY打开fifo的写入端。

关于c - 使用 select() 和 O_NONBLOCK 从 FIFO 读取两个连续写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36806060/

相关文章:

c# - 如何确保只有我的程序可以访问命名管道?

c# - DocumentCollection.Open() 函数不工作 AutoCAD API

c - 如何在 C 中生成谢尔宾斯基三角形(递归)

c - 在 Julia 中声明 C void 指针的正确方法

php - 优化的 mySQL 表索引结构,可更快地 SELECT 大范围日常数据

mysql - 连接两个表和两个联结表

wcf - 通过命名管道从 Windows 服务( session #0)连接到桌面应用程序( session #1)

c - 单击鼠标时绘制多边形

c - 在多进程系统中使用 SQLAllocHandle(SQL_HANDLE_ENV, ...)

C - select() 似乎阻塞的时间比超时时间长