【问题标题】:How to serialize an object to send over network如何序列化对象以通过网络发送
【发布时间】:2011-03-16 17:31:06
【问题描述】:

我正在尝试序列化对象以仅使用 STL 通过套接字通过网络发送。我没有找到一种方法来保持对象的结构在另一个主机中反序列化。我尝试转换为string,转换为char*,我花了很长时间在互联网上搜索教程,直到现在我一无所获。

有没有办法只用 STL 做到这一点?

有什么好的教程吗?

我几乎正在尝试提升,但如果有如何使用 STL 来做到这一点,我想学习。

【问题讨论】:

标签: c++ linux serialization sockets stream


【解决方案1】:

你可以用任何东西进行序列化。所有序列化意味着您将对象转换为字节,以便您可以通过流(如std::ostream)发送它并与另一个(如std::istream)一起读取它。只需覆盖operator <<(std::ostream&, const T&)operator >>(std::istream&, T&),其中T 是您的每种类型。以及您的类型中包含的所有类型。

但是,您可能应该只使用一个已经存在的库(Boost 非常好)。像 Boost 这样的库可以为您做很多事情,比如字节排序、处理常见对象(比如数组和标准库中的所有内容)、提供执行序列化的一致方法和大量其他内容。

【讨论】:

  • 当前版本的 Boost.Serialization 是否处理字节顺序?它的早期版本仅支持开箱即用的非便携式二进制存档。
  • 那是多久以前的事了?图书馆的当前目标之一是:Data Portability - Streams of bytes created on one platform should be readable on any other. 所以我很确定。
【解决方案2】:

我的第一个问题是:你想要序列化还是消息传递?

起初可能看起来很愚蠢,因为您要求序列化,但后来我一直区分这两个术语。

  • 序列化是对您的内存进行快照并在以后恢复它。每个对象都表示为一个单独的实体(尽管它们可能是组合的)
  • 消息传递是将信息从一个点发送到另一个点。消息通常有自己的语法,可能无法反映您的业务模式的组织结构。

我经常看到人们在应该使用消息传递的地方使用序列化。这并不意味着序列化没有用,而是意味着您应该提前考虑。一旦决定序列化 BOM,就很难改变它,特别是如果您决定重新定位信息的某些部分(将其从一个对象移动到另一个对象)......因为那么您将如何解码“旧”序列化版本?

现在已经澄清了......

...我会推荐 Google 的 Protocol Buffer。

你可以使用 STL 完美地重写你自己的,但你最终会做已经完成的工作,除非你想从中学习,否则它是毫无意义的。

protobuf 的一大优点是它在某种程度上与语言无关:即您可以为 C++、Java 或 Python 生成给定消息的编码器/解码器。 Python 的使用非常适合消息注入(测试)或消息解码(检查记录消息的输出)。如果您使用 STL,这并不是一件容易的事。

【讨论】:

  • 这不仅仅是消息传递,我想序列化一个包含 int、string、double 等类型的类。我想序列化一个对象并将其发送到另一台主机并在该主机中反序列化它。谢谢你的回答。
  • 嗯,它仍然可以被认为是消息传递 :) 消息传递是关于发送信息,信息与您的业务模型的给定对象是否一致并不重要。
【解决方案3】:

我明白了!

我使用 stringstream 序列化对象,并使用 stringstream 的方法 str() 和 string 的 c_str() 将其作为消息发送。

看。

class Object {
public:
int a;
string b;

void methodSample1 ();
void methosSample2 ();

friend ostream& operator<< (ostream& out, Object& object) {
out << object.a << " " << object.b;   //The space (" ") is necessari for separete elements
return out;
}

friend istream& operator>> (istream& in, Object& object) {
in >> object.a;
in >> object.b;
return in;
}
};

/* Server side */
int main () {
Object o;
stringstream ss;
o.a = 1;
o.b = 2;
ss << o;    //serialize

write (socket, ss.str().c_str(), 20); //send - the buffer size must be adjusted, it's a sample
}

/* Client side */
int main () {
Object o2;
stringstream ss2;
char buffer[20];
string temp;

read (socket, buffer, 20);  //receive
temp.assign(buffer);
ss << temp;
ss >> o2;   //unserialize
}

我不确定是否有必要在序列化之前转换为字符串(ss

【讨论】:

  • Object.b 包含空格会怎样?
  • 一个错误。这是因为必须使用 getline 从 in 读取到字符串 b。点赞:getline (in, object.b) infriend istream& operator>> (istream& in, Object& object) intead in >> object.b.
【解决方案4】:

我认为您应该在您的项目中使用 google 协议缓冲区。在网络传输中,协议缓冲区在序列化结构化数据方面比 XML 具有许多优势。协议缓冲区:

更简单 小 3 到 10 倍 快 20 到 100 倍 不那么模棱两可 以编程方式生成更易于使用的数据访问类

等等。我认为你需要阅读https://developers.google.com/protocol-buffers/docs/overview 来了解 protobuf

【讨论】:

    【解决方案5】:

    通过网络套接字序列化 C++ 对象

    这已经晚了 6 年,但我最近遇到了这个问题,这是我在搜索如何通过 C++ 中的网络套接字序列化对象时遇到的线程之一。该解决方案仅使用 2 或 3 行代码。我找到了很多答案,但我发现最简单的方法是使用reinterpret_cast&lt;obj*&gt;(target) 将类或结构转换为字符数组并通过套接字提供它。这是一个例子。

    要序列化的类:

    /* myclass.h */
    
    #ifndef MYCLASS_H
    #define MYCLASS_H
    
    class MyClass
    {
        public:
            int A;
            int B;
            MyClass(){A=1;B=2;}
            ~MyClass(){}
    };
    
    #endif
    

    服务器程序:

    /* server.cpp */
    
    #include "myclass.h"
    
    int main (int argc, char** argv)
    {
        // Open socket connection.
        // ...
    
        // Loop continuously until terminated.
        while(1)
        {
            // Read serialized data from socket.
            char buf[sizeof(MyClass)];
            read(newsockfd,buf, sizeof(MyClass));
            MyClass *msg = reinterpret_cast<MyClass*>(buf);  
    
            std::cout << "A = " << std::to_string(msg->A) << std::endl;
            std::cout << "B = " << std::to_string(msg->B) << std::endl;
        }
    
        // Close socket connection.
        // ...
    
        return 0;
    }
    

    客户程序:

    /* client.cpp */
    
    #include "myClass.h"
    
    int main(int argc, char *argv[])
    {
        // Open socket connection.
        // ...
    
        while(1)
        {
            printf("Please enter the message: ");
            bzero(buffer,256);
            fgets(buffer,255,stdin);
    
            MyClass msg;
            msg.A = 1;
            msg.B = 2;
    
            // Write serialized data to socket.
            char* tmp = reinterpret_cast<char*>(&msg);
            write(sockfd,tmp, sizeof(MyClass));
        }
    
        // Close socket connection.
        // ...
    
        return 0;
    }
    

    使用g++-std=c++11 编译server.cppclient.cpp选项。然后,您可以打开两个终端并运行这两个程序,但是,在客户端之前启动服务器程序,以便它可以连接到一些东西。

    希望这会有所帮助。

    【讨论】:

    • 警告:如果对象不是微不足道的(标准布局、两台机器上相同的填充、相同的字节序...),则会中断。
    猜你喜欢
    • 1970-01-01
    • 2014-12-16
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多