收到的 Protobuf 对象不具有所有字段
Posted
技术标签:
【中文标题】收到的 Protobuf 对象不具有所有字段【英文标题】:Protobuf object received does not have all fields 【发布时间】:2015-03-26 20:40:39 【问题描述】:我正在使用 ONCRPC 和 Google Protobuf 创建 HDFS 的 c++ 实现。我面临的问题是我正在发送一个填充了多个字段的 protobuf 对象(发送序列化字符串,在接收端对其进行解析),但是,在接收端它错误地表示其中一个字段具有未设置/不存在。
这是我 hdfs.proto 文件的一部分:
message AssignBlockRequest
optional int32 handle = 1; // obtain using call to OpenFile
message AssignBlockResponse
optional int32 status = 1;
optional BlockLocations newBlock = 2;
message BlockLocations
optional int32 blockNumber = 1;
repeated DataNodeLocation locations = 2;
message DataNodeLocation
optional string ip = 1;
optional int32 port = 2;
我在“客户端”应用程序中使用它来查询“名称节点服务器”以获取新块和它可以发送数据写入的数据节点位置列表。
所以,在我的客户中:
AssignBlockResponse assignnewblock_ ( int fhandle, CLIENT* clnt )
AssignBlockRequest req;
req.set_handle(fhandle);
//send request to nn
string str;
req.SerializeToString(&str);
static char *cstr = new char[str.length() + 1];
memcpy(cstr, str.c_str(), str.length()+1);
char **result_abreq;
result_abreq = assignblock_1( &cstr, clnt );
//handle response
AssignBlockResponse rsp;
string str_arg (*result_abreq);
rsp.ParseFromString(str_arg);
cout << "NN RETURNED : " << rsp.status() << " " << rsp.has_newblock() << endl;
return rsp;
在我的 namenode server.cc 中
char **
assignblock_1_svc(char **argp, struct svc_req *rqstp)
AssignBlockRequest req;
string str_arg (*argp);
req.ParseFromString(str_arg);
AssignBlockResponse rsp;
if ( DataNodeList.empty() ) // no DN available
rsp.set_status (1);
else
rsp.set_status (0);
int BL_NUM = 0;
vector<int> shuf;
BlockLocations bl;// = new BlockLocations;
bl.set_blocknumber(BL_NUM);
rsp.mutable_newblock()->CopyFrom(bl);
cout << "NN RETURNED : " << rsp.status() << " " << rsp.has_newblock() << endl;
string str;
rsp.SerializeToString(&str);
static char *cstr = new char[str.length() + 1];
memcpy(cstr, str.c_str(), str.length()+1);
return &cstr;
NN 输出“0 1”,而客户端在收到此 AssignBlockResponse 类型请求时显示“0 0”,即它获得正确的状态(通过更改 AssignBlockResponse 消息中设置的状态进行测试),但从未检测到“newblock” server.cc 发送给它的字段。
任何帮助将不胜感激。
-- 编辑 1--
Protocol buffer serializing with inheritance. Derived classes are empty
这可能很有趣。但是,我仍然无法让我的代码工作。
【问题讨论】:
【参考方案1】:我在早期使用协议缓冲区时遇到过这个问题。
不要序列化ToString。 serializeToArray 首先构建了一个足够大的向量(在消息上调用 ByteSize())
问题是您的序列化字节流包含一个零字节,在将 char* 转换为字符串时将其解释为字符串结尾。
这意味着您最终会解析不完整的消息,因此会丢失字段。
【讨论】:
我将其更改为使用 SerializeToArray 和 ParseFromArray,但无济于事。我确信您的建议应该可行,但我的代码仍然失败。 我确实让它工作了,但只有在客户端大小对象的 ParseFromArray 中硬编码对服务器端对象的 ByteSize() 调用的值时。有没有一种好方法可以通过网络发送 ByteSize() 的值/从收到的 c_str 中找出 ByteSize?我也可以使用状态字段来存储它。谢谢! 啊,那是另一回事。 protobuf 没有“框架”的概念。您必须使用自己的帧协议发送消息。 Parse 函数期望在一个完整的帧上工作。 一些非常简单的东西,比如 4 字节长度(按网络字节顺序),然后是序列化字节,然后(如果你偏执的话)数据的 crc 或校验和将是一个合理的框架协议通过tcp。如果您通过 http 发送,那么 http 协议当然有 Content-Length: 标头。AssignBlockResponse rsp; rsp.ParseFromString(*result_abreq); int size = rsp.status(); rsp.ParseFromArray(*result_abreq, size);
我将 ByteSize() 结果设置为 AssignBlockResponse 的状态字段,它似乎可以工作。请让我知道这是否有任何潜在的警告。以上是关于收到的 Protobuf 对象不具有所有字段的主要内容,如果未能解决你的问题,请参考以下文章
ProtoBuf-Net 错误消息“源数据中的无效字段:0”