在接收器端Boost Asio读取序列化的结构 [英] Reading a serialized struct at the receiver end boost asio

查看:121
本文介绍了在接收器端Boost Asio读取序列化的结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来的推动者和人脉;)。我正在使用boost :: asio制作客户端服务器应用程序,我需要将结构作为消息传递给 boost :: asio :: serialization

I am new to boost and networking ;). I am making a client server application with boost::asio, I need to pass structs as messages so used boost::asio::serialization for it :

test.h

#pragma once

#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
struct Test
{
    public:
        int a;
        int b;
        template<typename archive> void serialize(archive& ar, const unsigned version) {
        ar & a;
        ar & b;
    }
};

客户端发送:

void send_asynchronously(tcp::socket& socket) {
        Test info;

        info.a = 1;
        info.b = 2;

        {
            std::ostream os(&buf);
            boost::archive::binary_oarchive out_archive(os);
            out_archive << info;
        }

        async_write(socket, buf, on_send_completed);
    }

在接收方,我将数据读入 boost :: asio :: buffer ,我想知道一种解析此缓冲区并在服务器端提取对象的方法。请帮助。

On the receiver side, I read the data into a boost::asio::buffer, I want to know a way to parse this buffer and extract the object on server side. Please help.

推荐答案

您没有显示足够的代码来知道如何声明 buf 或管理整个生命周期。

You don't show enough code to know how you declared buf or managed the lifetime.

我假设您使用了 boost :: asio :: streambuf buf; 并且具有静态存储持续时间(命名空间范围)或为类成员(但您没有显示类)。

I'm assuming you used boost::asio::streambuf buf; and it has static storage duration (namespace scope) or is a class member (but you didn't show a class).

无论哪种方式,无论您拥有什么可以反向执行相同操作。

Either way, whatever you have you can do "the same" in reverse to receive.

这里是一个简化的版本(省略了异步操作,因此我们不必对事物的寿命进行猜测就像我上面提到的);

Here's a shortened version (that leaves out the async so we don't have to make guesses about the lifetimes of things like I mentioned above);

让我们连接到虚拟服务器(我们可以在下面做一个)在本地主机上的端口3001上:

Let's connect to an imaginary server (we can make one below) at port 3001 on localhost:

asio::io_context ioc;
asio::streambuf buf;
tcp::socket s(ioc, tcp::v4());
s.connect({{}, 3001});



序列化



基本上,您拥有:

Serialize

Basically what you had:

{
    std::ostream os(&buf);
    boost::archive::binary_oarchive oa(os);

    Test req {13,31};
    oa << req;
}

请注意流/归档的{}范围以确保归档已完成在发送之前。

Note the {} scope around the stream/archive make sure the archive is completed before sending.

/*auto bytes_sent =*/ asio::write(s, buf);



接收



假设我们的服务器发送了返回另一个以相同方式序列化的 Test 对象。

读入缓冲区,假设没有成帧,我们只是读取到流的末尾:

Reading into the buffer, assuming no framing we'll just "read until the end of the stream":

boost::system::error_code ec;
/*auto bytes_received =*/ asio::read(s, buf, ec);
if (ec && ec != asio::error::eof) {
    std::cout << "Read error: " << ec.message() << "\n";
    return 1;
}




在现实生活中,您需要超时和限制读取的数据量。通常,您的协议会在您知道要读取的数据量或预期的边界标记的地方添加成帧。

In real life you want timeouts and limits to the amount of data read. Often your protocol will add framing where you know what amount of data to read or what boundary marker to expect.



反序列化



Deserialize

Test response; // uninitialized
{
    std::istream is(&buf);
    boost::archive::binary_iarchive ia(is);

    ia >> response;
}



完整演示



在Coliru上直播

Full Demo

Live On Coliru

#include <boost/asio.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <iostream>
namespace asio = boost::asio;
using tcp = boost::asio::ip::tcp;

struct Test {
    int a,b;
    template<typename Ar> void serialize(Ar& ar, unsigned) { ar & a & b; }
};

int main() {
    asio::io_context ioc;
    asio::streambuf buf;
    tcp::socket s(ioc, tcp::v4());
    s.connect({{}, 3001});

    ///////////////////
    // send a "request"
    ///////////////////
    {
        std::ostream os(&buf);
        boost::archive::binary_oarchive oa(os);

        Test req {13,31};
        oa << req;
    }
    /*auto bytes_sent =*/ asio::write(s, buf);

    /////////////////////
    // receive "response"
    /////////////////////

    boost::system::error_code ec;
    /*auto bytes_received =*/ asio::read(s, buf, ec);
    if (ec && ec != asio::error::eof) {
        std::cout << "Read error: " << ec.message() << "\n";
        return 1;
    }

    Test response; // uninitialized
    {
        std::istream is(&buf);
        boost::archive::binary_iarchive ia(is);

        ia >> response;
    }

    std::cout << "Response: {" << response.a << ", " << response.b << "}\n";
}

使用netcat模拟具有先前生成的响应测试{42,99} (此处编码为base64):

Using netcat to mock a server with a previously generated response Test{42,99} (base64 encoded here):

base64 -d <<<"FgAAAAAAAABzZXJpYWxpemF0aW9uOjphcmNoaXZlEgAECAQIAQAAAAAAAAAAKgAAAGMAAAA=" | nc -N -l -p 3001

打印如下:

Response: {42, 99}  






¹具有相同的体系结构,并使用相同版本的boost进行编译,因为Boost的二进制归档文件不可移植。 实时演示很好地说明了这一点

这篇关于在接收器端Boost Asio读取序列化的结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆