3

我需要创建与 C++ 客户端和 Python 服务器的 TCP 聊天(已经开始),我在 C++ 类中有消息,例如

class Message{
public:
uint64 utc_time;
uint64 token;
string content;
};

我将这个从客户端发送到服务器,在服务器上我有 utc_time 的优先级队列,需要广播给其他人。我的问题是如何序列化这个,使用哪种格式以避免对大小类型 size 的任何跨语言依赖?(也许将来会有更多元数据,所以需要有点通用)?谁能给我建议使用哪种格式进行序列化(或仅刷新字节)?

class Persistent:
public:
    Persistent(int sz):objSize(sz){}
    void write(std::ostream& out)const{out.write((char*)this, objSize);}
    void read(std::istream& in){in.read((char*)this, objSize);}
private:
    int objSize;
};

我想到了在服务器上使用 c++ 反序列化器并在可能的情况下从 python 调用的其他可能性。这个问题有什么优雅的解决方案吗?

4

3 回答 3

4

如果您真的想跨语言和跨平台而不必担心消息在哪里结束,请查看Google ProtobufZeroMQ的组合。

使用常规套接字时,您将首先读取消息的大小(您将在前面添加它),然后您会知道字节数组从哪里到哪里是一个完整的消息。

protobuf + zmq 用法示例:

message Message {
    optional uint64 utc_time = 1;
    required uint64 token = 2;
    optional string content = 3;
}

使用 protobuf 编译器生成 C++ 代码(或 ruby​​/python/etc)。

要在您的代码中使用它:

#include <Message.pb.h>

Message msg;
msg.set_token(1);
msg.set_content("Hello world");

要使用 zmq 发送它:

std::string serialized = msg.SerializeAsString();
zmq::message_t reply(serialized.size());
memcpy(reply.data(), serialized.data(), serialized.size());
zmq_socket.send(reply);

要使用 zmq 接收它:

zmq::message_t request;
zmq_socket.recv(&request); // blocking
Message recv_msg;
recv_msg.ParseFromArray(request.data(), request.size());
于 2012-12-05T04:50:09.020 回答
1

使用 ZeroMQ 是一个好的开始,因为它会为您处理所有传输工作。序列化的最佳方式取决于您正在做的工作类型。由于您正在做一个聊天应用程序,效率不是问题,所以我会使用自描述文本格式,它最易于调试、跟踪、记录和使用。像 protobufs 或 msgpack 这样的任何东西都将是额外的工作,没有可衡量的回报。您可以使用 XML、JSON、HTTP 样式的标头、名称=值对等。

当您开始制作非常大量的消息(每秒数十万条)或非常大的消息(例如超过 1K 字节)时,您可以开始考虑减少消息大小的不同方法。我个人建议坚持使用最简单的文本格式,直到您确实遇到性能问题,然后在需要它的情况下切换到最有效的二进制格式。但不是在聊天应用程序中...

于 2012-12-06T19:25:21.317 回答
1

我喜欢使用 JSON,假设您有一个良好的套接字缓冲接口和一个基于流的 JSON 解析器。JSON 的好处是您不需要指定每条消息的长度。正确编写的 JSON 解析器可以判断它何时到达“对象”的末尾。因此,您的阅读器对象可以只解析通过网络传输的 JSON,当您到达初始对象的末尾时,将其作为一条消息返回给系统。

如果 JSON 对于您的数据来说太过分了,那么总会有纯文本。大多数互联网以纯文本(POP、IMAP、HTTP、FTP 等)运行。那是因为纯文本是使用跨平台/跨语言最简单的方法。

于 2012-12-06T20:45:09.043 回答