简体   繁体   English

读取命名管道不会刷新它

[英]Reading named pipe does not flush it

This is my first test on using unix named pipes. 这是我第一次使用unix命名管道。 Below is a simple example which tries to read a given pipe every second and, on success, outputs "triggered" to stdout. 下面是一个简单的示例,该示例尝试每秒读取给定管道,并在成功后将“触发”输出到stdout。 Using a bash script I can write that value to the pipe which is read by the program as expected. 使用bash脚本,我可以将该值写入程序按预期读取的管道。

The problem is, that the program keeps reading the value on every following loop although it is only written once to the pipe. 问题是,尽管程序仅被写入管道一次,但程序仍继续在每个后续循环中读取该值。 Every tutorial I could find tells me, everything which is read from the pipe is basically removed and if one wants to flush a pipe simply read everything. 我能找到的每个教程都告诉我,从管道中读取的所有内容基本上都已删除,如果要冲洗管道,则只需读取所有内容。 But the program below keeps outputting the value over and over without new input. 但是下面的程序会不断重复输出该值,而无需新输入。

main.cpp main.cpp

// std
#include <iostream>
// unix
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>


int main(int argc, char* argv[]) {

    // create named pipe
    mkfifo("/tmp/alarm_motion", 0666);

    for(;;){

        int fifo = open("/tmp/alarm_motion", O_RDONLY | O_NONBLOCK);
        char temp[sizeof(int)];
        int st = read(fifo, temp, sizeof(temp));
        if(st == 0){
            int res = atoi(temp);
            std::cout << "fifo" << res;
            if(res == 1){
                std::cout << " -> triggered";
                    close(fifo);
            }
            std::cout << std::endl;
        }
        sleep(1);
    }
}

test.sh test.sh

#!/bin/bash
pipe=/tmp/alarm_motion
echo 1 > $pipe

If I compile the program, start it, and execute the script after a few cycles, I receive the output below 如果我编译程序,启动它,并在几个周期后执行脚本,我将收到以下输出

sample output 样本输出

fifo0
fifo0
fifo0
fifo0
fifo0
fifo0
fifo1 -> triggered
fifo1 -> triggered
fifo1 -> triggered
fifo1 -> triggered
fifo1 -> triggered
fifo1 -> triggered

while I would expect the following output 而我期望以下输出

desired output 期望的输出

fifo0
fifo0
fifo0
fifo0
fifo0
fifo0
fifo1 -> triggered
fifo0
fifo0
fifo0
fifo0
fifo0

Can somebody tell me what I am doing wrong here? 有人可以告诉我我在做什么错吗?

g++ (Raspbian 4.9.2-10) on Raspbian 8 Raspbian 8上的g ++(Raspbian 4.9.2-10)

You have some serious flaws in your program: 您的程序中存在一些严重的缺陷:

  • An integer in text form may be much larger than the size of an int . 以文本形式的整数可以比的尺寸大得多 int For example the text "12345678" is eight bytes (not including string terminator!) which should be compared to the usual size of 4 for sizeof(int) . 例如,文本"12345678"八个字节(不包括字符串终止符!),应将其与sizeof(int)的通常大小4进行比较。

  • Nothing says that the data you read will be zero-terminated. 什么也没有说您读取的数据将以零结尾。 That means all functions that treat the data you read as a zero-terminated string (like eg atoi ) will not work reliably. 这意味着所有将您读取的数据视为零终止字符串的函数(例如atoi )将无法可靠运行。

  • The read function returns 0 when the pipe has been closed by the other end. 当管道的另一端已关闭时, read函数将返回0 Which means the data you attempt to use doesn't really exist. 这意味着您尝试使用的数据实际上并不存在。 The read call (after returning 0 ) haven't actually read anything. read调用(返回0 )实际上没有读取任何内容。

  • You have a serious resource leak, as you open the pipe over and over again without closing it. 当您反复open管道而不关闭管道时,资源泄漏很严重。

  • You have no error handling what so ever. 您从未如此处理任何错误。

Finally, that you seem to be reading the same data over and over is probably because of how the compiler have implemented your temp array. 最后,您似乎一遍又一遍地读取相同的数据,可能是由于编译器如何实现了temp数组。 It simply reuses the same memory. 它只是简单地重用相同的内存。 Since you just continue to loop over and over again you will see the same data over and over again since the location of the array is the same and the compiler (or your program) have cleared the memory in any way in between. 因为您只是继续反复循环,所以您将一遍又一遍地看到相同的数据,因为数组的位置是相同的,并且编译器(或您的程序)以其间的任何方式清除了内存。 The pipe is flushed, your memory contents is not. 管道被冲洗,您的内存内容没有被冲洗。

int st = read(fifo, temp, sizeof(temp));

This returns -1 on error, zero at end of stream, or a positive integer denoting the number of bytes that have been transferred. 错误返回-1,流末返回零,或表示已传输字节数的正整数。

Therefore this: 因此:

    if(st == 0){
        int res = atoi(temp);
        std::cout << "fifo" << res;
        if(res == 1){
            std::cout << " -> triggered";
                close(fifo);
        }
        std::cout << std::endl;
    }

makes no sense. 没有意义。 This block is what you should do if st is positive. 如果st正,则应执行此块操作 If it is zero you should close the pipe and exit the loop; 如果为零,则应关闭管道并退出循环; if it is -1 you should call perror() , close the pipe, and exit the loop. 如果为-1,则应调用perror() ,关闭管道,然后退出循环。

At present you are reading until end of stream, then printing the last thing you received, forever. 目前,您正在阅读直到流媒体结束,然后永远打印最后收到的内容。

You should also open the pipe prior to the loop. 您还应该在循环之前打开管道。 You can also get rid of the sleep() . 您还可以摆脱sleep() The read() will block while no data is available. 没有可用数据时, read()将阻塞。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM