FIFO管道中的数据丢失?

Posted

技术标签:

【中文标题】FIFO管道中的数据丢失?【英文标题】:Loss of data in a FIFO pipe? 【发布时间】:2015-05-06 22:39:56 【问题描述】:

我有一个 python 进程写入一个命名管道,一个 C++ 程序读取它。 (我用 C++ 创建管道)。嗯,它似乎工作正常。但是,有时我注意到有数据丢失。读取器未检测到数据!我做错了吗?

这是我创建管道的方式:

void create_pipes(string pipename)

    char * cstr1 = new char [pipename.length()+1];
    strcpy (cstr1, pipename.c_str());

    cout << "Creating " << pipename << " pipe..." << endl;
    unlink (cstr1); // Delete pipe
    int result = mkfifo (cstr1, S_IRUSR| S_IWUSR);  // Create Pipe
    if( result == -1 )
         cout << "There was en error creating the pipe! " << result << endl;
         //return 0;
    
    else
        cout << "Pipe created!" << endl;

现在,我有一个线程可以像这样读取管道:

     int fd = open(cstr1, O_RDONLY);  // Open the pipe


    while( running_threads )

        if(!read(fd, buf, MAX_BUF))
            continue;
        string line(buf);
        if( buf != "" )
            //cout << line;
            pipe_r.DECODE_PIPE_DATA(line);
        
    

    cout << "Thread terminated" << endl;

    close(fd);

在 python 中,我只是通过这样做将数据写入管道:

def write_pipe(file_string):
    while True:
        try:
            pipe.write(file_string)
            pipe.flush()
            break
        except:
            print "Error while writing to pipe"
            continue

什么可能导致我的问题? python程序将数据写入管道成功;但是 c++ 程序有时不会读取管道。这可能是由于 python 进程在实际读取数据之前写入数据的速度比 C++ 程序快吗?我该怎么办?

谢谢。

【问题讨论】:

Tangent:为什么不直接将pipename.c_str() 传递给unlinkmkfifo?您编写的代码不必要地分配内存(然后忘记释放它)。 if(!read(fd, buf, MAX_BUF)) -- 你把read的结果扔掉了,所以你不知道你读了多少数据。代码不可能工作。 【参考方案1】:

buf 不保证会被终止,也不保证不会在您发布的代码中嵌入'\0' 字符。这应该会更好,但如果 Python 代码在其写入的数据中嵌入 '\0',则仍可能会失败:

while( running_threads )

    ssize_t bytesRead = read(fd, buf, MAX_BUF);
    if ( bytesRead < 0 )
         break;
    else if ( bytesRead == 0 )
         continue;

    string line( buf, static_cast<size_t>(bytesRead) );

如果read() 返回 -1,您的代码没有正确处理错误情况。

【讨论】:

即使有嵌入的空值也应该可以工作。 std::string 可以包含任意数据。 @Brian,真的。但他使用的构造函数假定 C 风格的字符串是输入数据。 (我承认buf 被定义为char *char []。) 我的意思是,你的代码使用了正确的构造函数,所以它不会遇到同样的问题。还是我误会了什么? 我使用了指定输入字符串长度的构造函数。我不记得如果 '\0' 嵌入到带有该构造函数的这样的字符串中会发生什么。这就是为什么我说它“可能仍然失败”。但它确实可以防止溢出,而原始代码没有。根据cplusplus.com/reference/string/string/string,string( const char *, size_t ) 构造函数复制指定的字节数。所以它应该工作。但我不记得曾经使用过那个构造函数。 所以要明确一点...我的 python 代码不应该发送 '\0' 字符?

以上是关于FIFO管道中的数据丢失?的主要内容,如果未能解决你的问题,请参考以下文章

Hyper-V:通过命名管道连接 VM 会丢失数据

为啥这里举例说明在 LINUX 中使用命名管道 -FIFO 的程序会遇到竞争条件?

您如何处理 Apache Pig 中的空输入文件或丢失的输入文件?

spark-ml 规范化器丢失元数据

如何在不丢失或复制任何记录的情况下移动或更改管道

如何在不丢失科学记数法的情况下将列转换为单个管道分隔的列?