假设我有一个结构体,其中包含我想要使用winsock 2将其成员值发送到另一个系统的内容。 我正在使用C ++语言。
如何将其转换为char *,并考虑在发送之前必须对结构进行序列化,以及如何在另一端将char *反序列化为结构?我发现boost序列化被建议用于类似的问题,但是否可以用简短的代码片段说明序列化和反序列化的过程?
这个问题可能看起来很基础,但其他相关帖子中的答案并没有提供太多帮助。
这个问题可能看起来很基础,但其他相关帖子中的答案并没有提供太多帮助。
以下示例展示了将struct
序列化为char
数组并进行反序列化的最简单方法。
#include <iostream>
#include <cstring>
#define BUFSIZE 512
#define PACKETSIZE sizeof(MSG)
using namespace std;
typedef struct MSG
{
int type;
int priority;
int sender;
char message[BUFSIZE];
}MSG;
void serialize(MSG* msgPacket, char *data);
void deserialize(char *data, MSG* msgPacket);
void printMsg(MSG* msgPacket);
int main()
{
MSG* newMsg = new MSG;
newMsg->type = 1;
newMsg->priority = 9;
newMsg->sender = 2;
strcpy(newMsg->message, "hello from server\0");
printMsg(newMsg);
char data[PACKETSIZE];
serialize(newMsg, data);
MSG* temp = new MSG;
deserialize(data, temp);
printMsg(temp);
return 0;
}
void serialize(MSG* msgPacket, char *data)
{
int *q = (int*)data;
*q = msgPacket->type; q++;
*q = msgPacket->priority; q++;
*q = msgPacket->sender; q++;
char *p = (char*)q;
int i = 0;
while (i < BUFSIZE)
{
*p = msgPacket->message[i];
p++;
i++;
}
}
void deserialize(char *data, MSG* msgPacket)
{
int *q = (int*)data;
msgPacket->type = *q; q++;
msgPacket->priority = *q; q++;
msgPacket->sender = *q; q++;
char *p = (char*)q;
int i = 0;
while (i < BUFSIZE)
{
msgPacket->message[i] = *p;
p++;
i++;
}
}
void printMsg(MSG* msgPacket)
{
cout << msgPacket->type << endl;
cout << msgPacket->priority << endl;
cout << msgPacket->sender << endl;
cout << msgPacket->message << endl;
}
new
。以下是进一步可能的改进:1. 将MSG作为反序列化函数的返回类型,而不是输出参数;2. 使用struct MSG{...};
代替typedef struct MSG{...}MSG;
,在C++中是相同的;3. 使用std::string
或std::vector<byte>
来保存序列化数据(并且完全放弃那个#define PACKETSIZE
),并将其用作serialize
函数的返回值,而不是输出参数(或者如果您坚持更改参数为char(&data)[PACKETSIZE]
)。 - Marian Spanik您可以直接执行
struct MyStruct {
int data;
char* someNullTerminatedName; // Assuming not larger than 1023 chars
std::ostream& serialize(std::ostream& os) const {
char null = '\0';
os.write((char*)&data, sizeof(data));
os.write(someNullTerminatedName, strlen(someNullTerminatedName));
os.write(&null, 1);
return os;
}
std::istream& deserialize(std::istream& is) {
char buffer[1024];
int i = 0;
is.read((char*)&data, sizeof(data));
do { buffer[i] = is.get(); ++i; } while(buffer[i] != '\0');
if (someNullTerminatedName != NULL) free(someNullTerminatedName);
someNullTerminatedName = (char*)malloc(i);
for (i = 0; buffer[i] != '\0'; ++i) {
someNullTerminatedName[i] = buffer[i];
}
return is;
}
};
由你来处理字节序和int类型大小的差异等问题。
举个例子:
MyStruct foo, bar;
std::stringstream stream;
foo.serialize(stream);
// ... Now stream.str().c_str() contains a char* buffer representation of foo.
// For example it might contain [ 1f 3a 4d 10 h e l l o w o r l d \0 ]
bar.deserialize(stream);
// ... Now bar is a copy, via a serial stream of data, of foo.
::memcpy(data, &your_struct, sizeof(YourStruct)));
在接收时反之亦然:
::memcpy(&your_struct, data, sizeof(YourStruct)));
其中,data为char*类型。请注意,您需要分配足够大的内存来存储数据,并在最后删除它。};
example ex;
ex.a = 1;
ex.b = 1.02;
ex.c = 1.040; ::memcpy(Buffer, &ex, sizeof(example)); retval = send(conn_socket, Buffer, sizeof(Buffer), 0); 在接收端: example ex; retval = recvfrom(msgsock,Buffer, sizeof(Buffer), 0, (struct sockaddr *)&from, &fromlen); ::memcpy(&ex, Buffer, sizeof(example)); printf("%f", ex.c); 输出结果为:-62774385622041925000000000000000000000000000000。这是为什么呢? - Vigo好的,我将从boost网站上获取示例,因为我不明白你无法理解它的内容。
我添加了一些注释和更改,以说明如何通过网络进行传输。网络代码本身不在这里。关于此,你可以查看boost::asio。
int main() {
// create and open a character archive for output
// we simply use std::strinstream here
std::stringstream ofs;
// create class instance
const gps_position g(35, 59, 24.567f);
// save data to archive
{
boost::archive::text_oarchive oa(ofs);
// write class instance to archive
oa << g;
// archive and stream closed when destructors are called
}
// now we have const char* ofs.str().c_str()
// transfer those bytes via network
// read them on the other machine
gps_position newg;
{
// create and open an archive for input
std::stringstream ifs(the_string_we_read_from_the_network);
boost::archive::text_iarchive ia(ifs);
// read class state from archive
ia >> newg;
// archive and stream closed when destructors are called
}
return 0;
}