我正在使用Protobuf在带有插槽的计算机之间更改数据。要传输数据,我使用以下方法:
myProtoMessage::Message m;
string s;
m.SerializeToString(&s);
const char *msg = s.c_str();
// Send msg through socket
但是,我注意到Protobuf无法读取任何非int类型的接收数据(它将其分配为0)。 果然,如果我不使用套接字,而是尝试将我的消息恢复到相同的代码段中,则会发生相同的情况:
myProtoMessage::Message m;
string s;
m.SerializeToString(&s);
const char *msg = s.c_str();
myProtoMessage::Message m2;
m.ParseFromString(msg); // my data is lost
我还指出:
myProtoMessage::Message m;
string s;
m.SerializeToString(&s);
const char *msg = s.c_str();
string(msg) == s; // 0
// Let's try it again
string s2;
int size_msg = sizeof(msg) / sizeof(char);
s2.assign(msg, size_msg);
s2 == s; // still 0
myProtoMessage::Message m2;
m.ParseFromString(s2); // the data is lost
那么,为什么我不能正确地将数据转换回字符串?如果是引用问题,为什么protobuf无法读取char数组数据或从char数组转换的字符串数据? 任何帮助将不胜感激。
我的代码的一个更好的例子: Protobuf消息(message.proto)
syntax = 'proto3';
package message;
message Message1{
uint64 time_us = 1;
uint32 id = 2;
}
message Message2{
uint64 id= 1;
double l1= 2;
double l2 = 3;
float l3 = 4;
enum MyEnum {
IDLE = 0;
}
MyEnum myEnum = 8;
}
message CompleteMessage{
Message1 message1 = 1;
Message2 message2 = 2;
}
我的代码:
#include <iostream>
#include "message.pb.h"
#include "boost/asio.hpp"
using namespace boost::asio;
using namespace std;
// Send data through socker
void send_message(const char* msg, int msg_size, const char* IP, int port)
{
io_service io_service;
ip::udp::socket socket(io_service);
ip::udp::endpoint remote_endpoint;
socket.open(ip::udp::v4());
remote_endpoint = ip::udp::endpoint(ip::address::from_string(IP), port);
boost::system::error_code err;
socket.send_to(buffer(msg, msg_size), remote_endpoint, 0, err);
socket.close();
}
// Fill message data
void fill_m1_data(message::Message1* msg, uint64_t time_us, uint32_t id)
{
msg->set_id(id);
msg->set_time_us(time_us);
}
// Fill message data
void fill_m2_data(message::Message2* msg, uint64_t loaded_mission_id,
double latitude, double longitude, float altitude,
message::Message2::MyEnum state)
{
msg->set_id(loaded_mission_id);
msg->set_l1(latitude);
msg->set_l2(longitude);
msg->set_l3(altitude);
msg->set_myEnum (state);
}
int main(int argc, char const *argv[])
{
message::CompleteMessage m;
fill_m1_data(m.mutable_message1(), 1, 1);
fill_m2_data(m.mutable_message2(), 1, 22.0, 42.0, 10.f,
message::Message2::MyEnum::MyEnum_IDLE);
// Convert protobuf data to string
string s;
m.SerializeToString(&s);
const char *msg = s.c_str();
// Check the data, everything is fine
cout << "message 2" << endl;
cout << m.message2().id() << endl;
cout << m.message2().l1() << endl;
cout << m.message2().l2() << endl;
cout << m.message2().l3() << endl;
cout << m.message2().myEnum() << endl;
cout << "message 1" << endl;
cout << m.message1().id() << endl;
cout << m.message1().time_us() << endl;
// Get back the data
message::CompleteMessage m2;
m2.ParseFromString(msg); // get data back
// converting msg back to string by the methods above yields the same results
cout << "message 2" << endl;
cout << m.message2().id() << endl;
cout << m.message2().l1() << endl; // 0, should be 22.0
cout << m.message2().l2() << endl; // 0, should be 42.0
cout << m.message2().l3() << endl; // 0, should be 10.0f
cout << m.message2().myEnum() << endl;
cout << "message 1" << endl;
cout << m.message1().id() << endl;
cout << m.message1().time_us() << endl;
// Send the message
send_message(msg, s.length() - 1, "192.168.0.0", 9000);
return 0;
}
Protobuf文档:https://developers.google.com/protocol-buffers/docs/cpptutorial
通过套接字发送和接收数据时,以下代码有效:
// send
string s;
msg.SerializeToString(&s);
void *buffer = malloc(s.size());
msg.SerializeToArray(buffer, s.size());
send(fd, buffer, s.size(), 0);
free(buffer);
// receive
numbytes = recv(connectfd, buf, MAXDATASIZE, 0);
buf[numbytes] = '\0';
// Receive msg from clients
message::CompleteMessage m;
m.ParsePartialFromArray(buf, sizeof(buf) / sizeof(char)); // sizeof(buf) / sizeof(char) can be changed to numbytes
不是最干净的,但是可以完成工作。关于字符串和char数组的问题仍然存在。
答案 0 :(得分:1)
从protobuf消息序列化的字符串是二进制字符串。您不能使用单个二进制char指针构造std::string
。相反,您还应该指定二进制字符串的大小。
myProtoMessage::Message m;
string s;
m.SerializeToString(&s);
const char *msg = s.c_str();
myProtoMessage::Message m2;
// in this case, msg will be converted to std::string,
// and will be truncated when it meets the first '\0'.
// That's why your data is lost
// m.ParseFromString(msg); // my data is lost
// Instead, you should call `ParseFromArray` to specify the size of the string buffer.
m.ParseFromArray(msg, s.size());
// Or construct a std::string manually.
m.ParseFromString(std::string(msg, s.size()));
myProtoMessage::Message m;
string s;
m.SerializeToString(&s);
const char *msg = s.c_str();
// Send msg through socket
// When you send msg, also specify the size of the message:
// send(sock, msg, s.size(), flags);