在 Linux 中使用 fgets 在 C 程序中命名管道删除数据

Named Pipe Dropping Data in C Program Using fgets in Linux

我正在尝试使用 fgets 从 C 程序 (gcc -std=c99) 中的命名管道中提取数据。我在命令行创建了管道,我可以看到它存在于文件系统中,并且在使用 "ls -la" 时用 p 停放并且权限设置为任何人都可以使用。

prw-rw-rw-  1 www-data www-data    0 Dec 23 00:39 mypipe

我正在使用一个简单的脚本将数据发送到管道:

#script
myPipe="/tmp/mypipe"
    for j in {0..255}
    do
#       echo "C $j"             #when this is enabled slightly more data gets through
        echo "C $j" >> $myPipe
#       sleep 0.00000000000001      #when this is enabled all the data gets through           
    done

我的程序试图从此管道读取的循环是:

void * reader(){

    int messages = 0;                           // keep track of how many messages we process
    char buf[PIPE_BUF];     buf[0] = 0;         //#defined  PIPE_BUF    1024
    int x=100, y=101, z=102, count=103;         //initialized to unlikely initial input results
    char linetag[PIPE_BUF]; linetag[0] = 0;     //space to store the data label
    char * pScan = NULL;
    FILE *myStream ;

    syslog (LOG_INFO, "Reader started\n");

    myStream = fopen(pipeName, "r");
    if ( myStream == NULL ) {
        syslog (LOG_INFO, "Could not open pipe %s as input to Cota\n", pipeName ) ;
        return 0;
    }
    while (1) {

        //>>> This was the problem and removing it seems to fix the issue
        //freopen(pipeName, "r", myStream);  <<<<This was the problem !!!!

        pScan==buf;
        syslog (LOG_INFO, "readp-1:msg:%i >>%s<<>>%s<< pBuf=%p, pScan=%p, count=%i, tag=%s, x=%d, y=%d, z=%d\n", messages, buf, pScan, buf, pScan, count, linetag, x,y,z);

        while ( (pScan = fgets(buf, PIPE_BUF, myStream)) == NULL){};

        if (pScan == NULL){syslog (LOG_WARNING, "ERROR NULL pScan error");}

        syslog (LOG_INFO, "readp-2:msg:%i >>%s<<>>%s<< pBuf=%p, pScan=%p, count=%i, tag=%s, x=%d, y=%d, z=%d\n", messages, buf, pScan, buf, pScan, count, linetag, x,y,z);

        count = sscanf(pScan, "%s %d %d %d", linetag, &x, &y, &z);

        syslog (LOG_INFO, "readp-3:msg:%i >>%s<<>>%s<< pBuf=%p, pScan=%p, count=%i, tag=%s, x=%d, y=%d, z=%d\n", messages, buf, pScan, buf, pScan, count, linetag, x,y,z);

        messages++;
    }
}

当我运行上面写的脚本时,我的系统日志显示如下:

Reader started
readp-1:msg:0 >><<>>(null)<< pBuf=0xbe885df4, pScan=(nil), count=103, tag=, x=100, y=101, z=102
readp-2:msg:0 >>C 0#012<<>>C 0#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=103, tag=, x=100, y=101, z=102
readp-3:msg:0 >>C 0#012<<>>C 0#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=0, y=101, z=102
readp-1:msg:1 >>C 0#012<<>>C 0#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=0, y=101, z=102
readp-2:msg:1 >>C 1#012<<>>C 1#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=0, y=101, z=102
readp-3:msg:1 >>C 1#012<<>>C 1#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=1, y=101, z=102
readp-1:msg:2 >>C 1#012<<>>C 1#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=1, y=101, z=102
readp-2:msg:2 >>C 10#012<<>>C 10#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=1, y=101, z=102
readp-3:msg:2 >>C 10#012<<>>C 10#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=10, y=101, z=102
readp-1:msg:3 >>C 10#012<<>>C 10#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=10, y=101, z=102
readp-2:msg:3 >>C 11#012<<>>C 11#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=10, y=101, z=102
readp-3:msg:3 >>C 11#012<<>>C 11#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=11, y=101, z=102
readp-1:msg:4 >>C 11#012<<>>C 11#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=11, y=101, z=102
readp-2:msg:4 >>C 15#012<<>>C 15#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=11, y=101, z=102
readp-3:msg:4 >>C 15#012<<>>C 15#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=15, y=101, z=102
readp-1:msg:5 >>C 15#012<<>>C 15#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=15, y=101, z=102
readp-2:msg:5 >>C 16#012<<>>C 16#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=15, y=101, z=102
readp-3:msg:5 >>C 16#012<<>>C 16#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=16, y=101, z=102
readp-1:msg:6 >>C 16#012<<>>C 16#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=16, y=101, z=102
readp-2:msg:6 >>C 18#012<<>>C 18#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=16, y=101, z=102
readp-3:msg:6 >>C 18#012<<>>C 18#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=18, y=101, z=102
readp-1:msg:7 >>C 18#012<<>>C 18#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=18, y=101, z=102
readp-2:msg:7 >>C 24#012<<>>C 24#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=18, y=101, z=102
readp-3:msg:7 >>C 24#012<<>>C 24#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=24, y=101, z=102
readp-1:msg:8 >>C 24#012<<>>C 24#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=24, y=101, z=102
readp-2:msg:8 >>C 39#012<<>>C 39#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=24, y=101, z=102
readp-3:msg:8 >>C 39#012<<>>C 39#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=39, y=101, z=102
readp-1:msg:9 >>C 39#012<<>>C 39#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=39, y=101, z=102
readp-2:msg:9 >>C 50#012<<>>C 50#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=39, y=101, z=102
readp-3:msg:9 >>C 50#012<<>>C 50#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=50, y=101, z=102
readp-1:msg:10 >>C 50#012<<>>C 50#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=50, y=101, z=102
readp-2:msg:10 >>C 70#012<<>>C 70#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=50, y=101, z=102
readp-3:msg:10 >>C 70#012<<>>C 70#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=70, y=101, z=102
readp-1:msg:11 >>C 70#012<<>>C 70#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=70, y=101, z=102
readp-2:msg:11 >>C 81#012<<>>C 81#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=70, y=101, z=102
readp-3:msg:11 >>C 81#012<<>>C 81#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=81, y=101, z=102
readp-1:msg:12 >>C 81#012<<>>C 81#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=81, y=101, z=102
readp-2:msg:12 >>C 108#012<<>>C 108#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=81, y=101, z=102
readp-3:msg:12 >>C 108#012<<>>C 108#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=108, y=101, z=102
readp-1:msg:13 >>C 108#012<<>>C 108#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=108, y=101, z=102
readp-2:msg:13 >>C 119#012<<>>C 119#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=108, y=101, z=102
readp-3:msg:13 >>C 119#012<<>>C 119#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=119, y=101, z=102
readp-1:msg:14 >>C 119#012<<>>C 119#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=119, y=101, z=102
readp-2:msg:14 >>C 136#012<<>>C 136#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=119, y=101, z=102
readp-3:msg:14 >>C 136#012<<>>C 136#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=136, y=101, z=102
readp-1:msg:15 >>C 136#012<<>>C 136#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=136, y=101, z=102
readp-2:msg:15 >>C 155#012<<>>C 155#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=136, y=101, z=102
readp-3:msg:15 >>C 155#012<<>>C 155#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=155, y=101, z=102
readp-1:msg:16 >>C 155#012<<>>C 155#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=155, y=101, z=102
readp-2:msg:16 >>C 172#012<<>>C 172#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=155, y=101, z=102
readp-3:msg:16 >>C 172#012<<>>C 172#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=172, y=101, z=102
readp-1:msg:17 >>C 172#012<<>>C 172#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=172, y=101, z=102
readp-2:msg:17 >>C 193#012<<>>C 193#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=172, y=101, z=102
readp-3:msg:17 >>C 193#012<<>>C 193#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=193, y=101, z=102
readp-1:msg:18 >>C 193#012<<>>C 193#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=193, y=101, z=102
readp-2:msg:18 >>C 213#012<<>>C 213#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=193, y=101, z=102
readp-3:msg:18 >>C 213#012<<>>C 213#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=213, y=101, z=102
readp-1:msg:19 >>C 213#012<<>>C 213#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=213, y=101, z=102
readp-2:msg:19 >>C 233#012<<>>C 233#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=213, y=101, z=102
readp-3:msg:19 >>C 233#012<<>>C 233#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=233, y=101, z=102
readp-1:msg:20 >>C 233#012<<>>C 233#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=233, y=101, z=102
readp-2:msg:20 >>C 246#012<<>>C 246#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=233, y=101, z=102
readp-3:msg:20 >>C 246#012<<>>C 246#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=246, y=101, z=102
readp-1:msg:21 >>C 246#012<<>>C 246#012<< pBuf=0xbe885df4, pScan=0xbe885df4, count=2, tag=C, x=246, y=101, z=102

数据分析似乎与行首的 'C' 正确对齐。如果在我的脚本中,我启用本地终端 echo 到屏幕,那么我会减少行数。如果我启用 sleep 0.00000000000001 我就可以读取所有数据。我真的需要它 运行 全速运行并且讨厌通过睡眠来减慢速度。我只是超过 运行 一个缓冲区吗?如果是,可以增加缓冲区大小吗?我真的很困惑。顺便说一句,我使用的是 fgets 而不是 fscanf,因为我最终需要添加 fastcgi 并且 fsastcgi 似乎缺乏对 fscanf 的支持(注意在这个测试中我使用的是标准 io 库,我没有在 fastcgi 中链接,我不包括"fcgi/include/fcgi_stdio.h" 在此测试中,因此没有覆盖默认库)。任何使它可靠和高效的方向将不胜感激。

FIFO 是有趣(奇特)的文件。一个读取进程在打开时阻塞,直到有一个写入器;一个写入进程在打开时阻塞,直到出现 reader。如果没有作者,reader 将得到 EOF;此时,它必须关闭 FIFO 并重新打开它以允许更多的写入器。如果没有readers或writer,则丢弃FIFO的内容。在您的 shell 脚本中,您重复打开和关闭 FIFO。您最好将 >> $myPipe 移动到循环的 done 行,这样 FIFO 打开一次,然后写入所有消息,然后 FIFO 关闭。

你的代码很奇特。这一行有问题:

while ((pScan = fgets(buf, PIPE_BUF, myStream)) == NULL){};

我看到两个问题。不太严重的是你在空循环body之后有一个空语句。除了向有经验的 reader 表明您对您的 C 代码没有信心之外,这不会做任何有害的事情。 {} 就足够了;这是一个空循环 body。下一行用分号代替 {} 是约定俗成的。

更严重的问题是,如果你进入循环,你将无限期地留在循环中。一旦 myStream 报告 EOF(通过从 fgets() 返回 NULL,它将无限期地继续这样做(除非你在 Linux 并且输入设备实际上是一个终端 -这对我来说是一个单独的痛点。

问题中的代码似乎是在被问到后被hack了,循环顶部的freopen()行被注释掉了,这就是'fixed'的问题。这是可以解释的。当 FIFO 关闭重新打开时,内容被丢弃。

更好的代码可能看起来更像这样。它将管道名称直接传递给函数(尽可能避免使用全局变量)。如果打开 FIFO 失败,该函数仅 returns。返回 NULL 的函数没有明显的需要或好处(写作 0 — 没关系;我也这样做),所以它现在是一个 void 函数。函数声明应该在 header 文件中,而不是在代码中内联。

总的来说,我会将大部分变量移动到更接近它们首次使用的位置——只有 messages 会留在无限循环之外。会有一个header来声明各种函数

#include <syslog.h>
#include <stdio.h>

#define PIPE_BUF 1024

extern void reader(const char *pipeName);

void reader(const char *pipeName)
{
    int messages = 0;
    char buf[PIPE_BUF];
    int x = 100, y = 101, z = 102, count = 103;
    char linetag[PIPE_BUF];

    syslog(LOG_INFO, "Reader started\n");

    while (1)
    {
        FILE *myStream = fopen(pipeName, "r");
        if (myStream == NULL)
        {
            syslog(LOG_INFO, "Could not open pipe %s as input to Cota\n", pipeName);
            return;
        }
        while (fgets(buf, sizeof(buf), myStream) != 0)
        {
            count = sscanf(buf, "%s %d %d %d", linetag, &x, &y, &z);
            syslog(LOG_INFO, "readp-3:msg:%i >>%s<< count=%i, tag=%s, x=%d, y=%d, z=%d\n",
                   messages, buf, count, linetag, x, y, z);
            messages++;
        }
        fclose(myStream);
    }

    /* NOTREACHED */
    syslog(LOG_INFO, "Reader finished\n");
}