将字符串转换为字符数组,然后再转换回字符串
Converting string to char array and then back into string
我正在使用 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
那么,为什么我不能正确地将数据转换回字符串?如果是reference的问题,为什么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
编辑 2
以下代码在通过套接字发送和接收数据时有效:
// 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] = '[=15=]';
// Receive msg from clients
message::CompleteMessage m;
m.ParsePartialFromArray(buf, sizeof(buf) / sizeof(char)); // sizeof(buf) / sizeof(char) can be changed to numbytes
不是最干净的,但也够用了。关于字符串和字符数组的问题仍然存在。
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 '[=10=]'.
// 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);
我正在使用 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
那么,为什么我不能正确地将数据转换回字符串?如果是reference的问题,为什么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
编辑 2
以下代码在通过套接字发送和接收数据时有效:
// 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] = '[=15=]';
// Receive msg from clients
message::CompleteMessage m;
m.ParsePartialFromArray(buf, sizeof(buf) / sizeof(char)); // sizeof(buf) / sizeof(char) can be changed to numbytes
不是最干净的,但也够用了。关于字符串和字符数组的问题仍然存在。
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 '[=10=]'.
// 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);