繁体   English   中英

读取管道(C / C ++),没有错误,但不是所有数据

[英]Read pipe (C/C++), no error, but not all data

在C ++程序中,我想获取python程序可以轻松提供的一些数据。 C ++程序调用popen() ,读取数据(序列化的protobuf)并继续。 这种方法运行良好,但最近由于接收到的字符串比发送的字符串短而开始失败。

我试图理解为什么我不阅读自己写的内容 (尽管没有错误报告)以及如何产生进一步的假设。 首先,这是在Linux(64位)上,并且两个进程都是本地的。 Python是2.7。

(确实,数据大小已经变大(现在是17MB,以前是500 KB),但这不会导致失败,尽管这是一个确定的信号,为了提高效率我需要进行一些更改。)

在python端,我计算了group_id映射到组的命令( RegistrationProgress ,请参见下面):

payload = RegistrationProgressArray()
for group_id, group in groups.items():
    payload.group.add().CopyFrom(group)
payload.num_entries = len(groups)
print('{a}, {p}'.format(a=len(groups), p=len(payload.group)),
      file=sys.stderr)
print(payload.SerializeToString())
print('size={s}'.format(s=len(payload.SerializeToString())),
      file=sys.stderr)

请注意, ap在python端匹配(正确!)。 大小约为17MB。 在C ++方面,

string FetchProtoFromXXXXX<string>(const string& command_name) {
    ostringstream fetch_command;
    fetch_command << /* ... */ ;
    if (GetMode(kVerbose)) {
        cout << "FetchProtoFromXXXXX()" << endl;
        cout << endl << fetch_command.str() << endl << endl;
    }
    FILE* fp = popen(fetch_command.str().c_str(), "r");
    if (!fp) {
        perror(command_name.c_str());
        return "";
    }
    // There is, sadly, no even remotely portable way to create an
    // ifstream from a FILE* or a file descriptor.  So we do this the
    // C way, which is of course just fine.
    const int kBufferSize = 1 << 16;
    char c_buffer[kBufferSize];
    ostringstream buffer;
    while (!feof(fp) && !ferror(fp)) {
        size_t bytes_read = fread(c_buffer, 1, kBufferSize, fp);
        if (bytes_read < kBufferSize && ferror(fp)) {
            perror("FetchProtoFromXXXXX() failed");
            // Can we even continue?  Let's try, but expect that it
            // may set us up for future sadness when the protobuf
            // isn't readable.
        }
        buffer << c_buffer;
    }
    if (feof(fp) && GetMode(kVerbose)) {
        cout << "Read EOF from pipe" << endl;
    }
    int ret = pclose(fp);
    const string out_buffer(buffer.str());
    if (ret || GetMode(kVerbose)) {
        cout << "Pipe closed with exit status " << ret << endl;
        cout << "Read " << out_buffer.size() << " bytes." << endl;
    }
    return out_buffer;
}

大小约为144KB。

我要发送的protobuf看起来像这样。 num_entries有点偏执,因为它应该与group_size()相同, group_size()group().size()

message RegistrationProgress { ... }

message RegistrationProgressArray {
required int32 num_entries = 1;
repeated RegistrationProgress group = 2;
}

那我跑的就是

array = FetchProtoFromXXXXX("my_command.py");
cout << "size=" << array.num_entries() << endl;
if (array.num_entries() != array.group_size()) {
    cout << "Something is wrong: array.num_entries() == "
         << array.num_entries()
         << " != array.group_size() == " << array.group_size()
         << " " << array.group().size()
         << endl;
    throw MyExceptionType();
}

运行它的输出是

122, 122
size=17106774
Read EOF from pipe
Pipe closed with exit status 0
Read 144831 bytes.
size=122
Something is wrong: array.num_entries() == 122 != array.focus_group_size() == 1 1

检查反序列化的protobuf,看来group是一个长度为一个的数组,只包含我期望的数组的第一个元素。

这个...

buffer << c_buffer;

...要求c_buffer包含ASCIIZ内容,但是在您的情况下,您不可以NUL终止它。

相反,请确保捕获了读取的确切字节数(即使存在嵌入的NUL ):

buffer.write(c_buffer, bytes_read);

您可以使用以下方法将每个块分类到输出buffer

buffer << c_buffer;

正如Tony D在回答中所解释的那样,在执行c_buffer之前,请不要对c_buffer终止之前将其终止,因此,如果c_buffer不包含嵌入式null字符,则会调用未定义的行为。

相反,如果c_buffer确实包含嵌入的空字符,则将剥离并忽略部分流。

您确定流协议不包含嵌入的'\\0'字节吗?

您还应该阅读为什么“ while(!feof(file))”总是错误的? 尽管就您而言,我认为这不是造成您的问题的原因。

暂无
暂无

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

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