You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FIFO管道读取最大元素数限制问题求助

FIFO管道读取最大元素数限制问题求助

我尝试编写一个简单的读写程序,使用FIFO管道进行通信。

Reader代码:

#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFSIZE 65600 //921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }

int main()
{
    int fd;
    ssize_t n;
    char buf[BUFFSIZE];
    long int i;

    if ( (fd = open("./shared/test", O_RDONLY)) < 0)
        err("open")

    while( (n = read(fd, buf, BUFFSIZE) ) > 0) {
        printf("Read (%d): ", n);
        for (i=0; i<BUFFSIZE; i++)
            printf("%c", buf[i]);
        printf("\n");
    }
    close(fd);
    
    return 0;
}

Writer代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFFSIZE  65600 //921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }


int main()
{
    int fd;
    char buf[BUFFSIZE];
    long int i, j;

    mkfifo("./shared/test", 0666);
    if ( (fd = open("./shared/test", O_WRONLY)) < 0)
        err("open")

    // main loop
    j=0;
    while (1){
    for (i=0;i<BUFFSIZE;i++){
        buf[i]= j + '0';
    }
    j++;
    buf[BUFFSIZE-1]=j + '0';
    
    write(fd, buf, sizeof(buf));
    sleep(10);
    }

    close(fd);
    
    return 0;
}

当BUFFSIZE设置为65535(2^16-1)时程序能正常工作,但改成更大的数值(比如65600)后,读取时会出现类似这样的情况:Read (65536): 0000000000000000000000000000000000000,后面跟着一堆垃圾数据。

请问如何让程序支持更大的元素数量?谢谢!
—— Joe


问题根源分析

这个问题的核心是FIFO管道的默认缓冲区大小限制。大多数系统中,管道(包括FIFO)的默认缓冲区大小是64KB(也就是65536字节)。当你尝试一次性写入超过这个大小的数据时,write调用会被阻塞直到有部分数据被读取,但你的读取逻辑存在两个关键问题:

  1. 读取长度处理错误:你在printf("Read (%d): ", n);中把ssize_t类型的n用%d格式化,更直接的问题是,read实际只能返回当前管道中可用的数据量——也就是默认的64KB,剩下的数据还在写入等待中,但你的代码却直接遍历整个BUFFSIZE长度的缓冲区,这就导致未被填充的部分输出垃圾数据。

  2. 循环读取不完整:你的读取逻辑只做了一次read就遍历整个缓冲区,但实际上当写入的数据超过管道缓冲区大小时,需要多次调用read才能把所有数据读完。

修正方案

1. 修复Reader的读取逻辑

需要循环读取直到获取到完整的BUFFSIZE字节数据,或者处理到文件结束。修改后的Reader代码如下:

#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define BUFFSIZE 65600 //921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }

int main()
{
    int fd;
    ssize_t n, total_read;
    char buf[BUFFSIZE];
    long int i;

    if ( (fd = open("./shared/test", O_RDONLY)) < 0)
        err("open")

    while(1) {
        total_read = 0;
        // 循环读取直到拿到完整的BUFFSIZE数据
        while (total_read < BUFFSIZE) {
            n = read(fd, buf + total_read, BUFFSIZE - total_read);
            if (n <= 0) {
                if (n == 0) {
                    // 写入端关闭,退出
                    close(fd);
                    return 0;
                } else {
                    err("read");
                }
            }
            total_read += n;
        }
        printf("Read (%zd): ", total_read);
        for (i=0; i<BUFFSIZE; i++)
            printf("%c", buf[i]);
        printf("\n");
    }
    close(fd);
    
    return 0;
}

2. 可选:调整FIFO缓冲区大小

如果你希望减少读取次数,可以通过fcntl系统调用调整FIFO的缓冲区大小(注意:这个操作需要系统支持,不同系统的上限不同)。在Writer打开FIFO后添加以下代码:

// 调整缓冲区大小为128KB(示例值,根据需求修改)
int pipe_size = 131072;
if (fcntl(fd, F_SETPIPE_SZ, pipe_size) == -1) {
    perror("fcntl F_SETPIPE_SZ failed");
    // 调整失败不终止程序,继续使用默认大小
}

额外注意事项

  • Writer的错误处理:当前Writer中的mkfifo调用没有错误处理,如果FIFO已经存在会报错,建议添加判断:
    if (mkfifo("./shared/test", 0666) == -1) {
        if (errno != EEXIST) {
            err("mkfifo");
        }
    }
    
  • 数据类型匹配:ssize_t对应的格式化符号是%zd,不要用%d,避免类型转换错误。

这样修改后,程序就能支持更大的BUFFSIZE值了。


备注:内容来源于stack exchange,提问作者user3318590

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 10:09:33