【问题标题】:Combine Multiple Data Types To Formulate A packet组合多种数据类型形成一个数据包
【发布时间】:2015-02-25 14:31:39
【问题描述】:

我正在尝试创建一个类,它将多种类型的变量组合成一个变量,该变量可用于发送到远程机器并根据这些数据重建类。

您将构建一个新数据包,该数据包将具有“数据变量”,不确定这应该是什么类型的变量,网络库允许将数据作为“const void *”发送

DataPacket *Packet = new DataPacket();

将数据添加到数据包中,这将传递您指定类型的值并将其“附加”到“数据变量”的末尾

Packet.AddData<int>(45);
Packet.AddData<bool>(true);
Packet.AddData<const char*>("Test");

发送数据包,这实际上会通过网络库将“数据变量”发送到远程机器

Packet.Send();

在接收机器上构造一个数据包,将我们发送的“数据变量”传递给它,这将构造一个从发送机器发送的数据包的副本

DataPacket *Packet = new DataPacket(Data);

每次调用 GetData 时,以与写入数据相同的顺序从“数据变量”中读取数据。

int Var1 = Packet.GetData<int>();
bool Var2 = Packet.GetData<bool>();
const char* Var3 = Packet.GetData<const char*>();

我很困惑的是这个“数据变量”应该是什么类型的变量,如何从这个“数据变量”构造一个相同的数据包,以及如何将变量放入和取出“数据变量”设置类似函数。

【问题讨论】:

  • 您正在寻找的是一个序列化库。试试Boost.Serialization
  • 我宁愿不使用 Boost
  • 你不应该重新发明轮子,尤其是在一个比最初看起来更棘手的领域...... ;-]

标签: c++ sockets templates c++11 packet


【解决方案1】:

编辑: 我似乎误解了你的问题。如果您想将数据传输到远程机器,即通过网络或其他方式,您需要像 Boost.Serialization 这样的序列化库:http://www.boost.org/doc/libs/1_55_0/libs/serialization/doc/index.html。将您的类型,尤其是非平凡类型转换为字节流,然后再将它们转换回来并不是一件容易的事。我会选择助推器。

我的原始答案仅适用于在进程内部而不是在进程外部发送数据:

如果您不想使用 boost.any 或 boost.variant,您可以使用 Sean Parent 提供的出色的非侵入式多态性模式自行开发:

class PacketData{
    struct Context {
        virtual ~Context() = default;
    };
    template<typename T>
    struct Instance : Context {
        Instance(T&& t):data_{std::move(t)}{

        }
        T data_;
    };
    std::unique_ptr<Context> self_;
    public:
    template<typename T>
    PacketData(T in):self_{new Instance<T>{std::move(in)}}{}
    //move is easy, copy is harder ;)

    template<typename T>
    bool isA(){
        return dynamic_cast<Instance<T>*>(self_.get()) != nullptr;
    }
    template<typename T>
    T& asA(){
        if(!isA<T>()){
            throw std::runtime_error("bad cast or something");
        }
        return dynamic_cast<Instance<T>*>(self_.get())->data_;
    }
};

制作这个变体类之后,剩下的应该很容易了:

using Packet = std::vector<PacketData>;


Packet packet;
packet.push_back(4);
packet.push_back(4.4f);
packet.push_back(std::string{"test"});
int i = packet[0].asA<int>();
float f = packet[1].asA<float>();
std::string s = packet[2].asA<std::string>();

这是一个活生生的例子:http://ideone.com/U7rmOL

如果你想要速度,你可以通过在 PacketData 类中放置一个堆栈分配器来绕过堆分配,该类足够大以容纳通常的数据大小。见http://home.roadrunner.com/~hinnant/stack_alloc.html

【讨论】:

  • 好的,现在完全理解如何设置和检索信息,但是如何将向量转换为可以传输的变量,然后作为向量重新组合在一起?
  • 只是一种风格挑剔:您似乎习惯于自动#include-ing &lt;iostream&gt; 并执行using namespace std;,即使在此示例中看不到 IOstream,并且您在每个标准库组件前加上 std::。此外,您不包括 &lt;string&gt;,由于某些不符合的原因,它会在您的特定平台上编译。
  • @TemplateRex ideone.com 包含 iostream 并在我扩展的默认模板中添加了 using 声明,我删除了它们以防止新手产生不好的想法并添加了包含字符串。
【解决方案2】:

GoingNative/channel9 中说明了一种技术(我似乎再也找不到了)。是这样的:

#include <vector>

class Packet
{
    class Generic
    {};

    template <typename C>
    class Content : public Generic
    {
        C content;
    public:
        Content() : Generic(), content() {}
        Content(const C& c) : Generic(), content(c) {}
        ~Content() {}

        C& getContent() const { return content; }
    };

    std::vector<Generic> packet_content;

public:
    Packet() : packet_content() {}

    template <typename X>
    void add(X x) { packet_content.push_back(Content<X>(x)); }
};


int main()
{
    Packet packet;
    packet.add(5);
    packet.add(std::string("hello"));
    packet.add(55);
    packet.add(false);
    packet.add(std::string("world"));
}

【讨论】:

  • 这样的东西正是我想要的。然后我怎样才能反过来用 auto var = packet.get(); 之类的函数读回数据;
  • 您想到的演示文稿来自 Sean parent
  • 抱歉偷了你的主意,我确实等了一天才发帖;)
猜你喜欢
  • 1970-01-01
  • 2015-03-01
  • 2015-09-20
  • 1970-01-01
  • 2012-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多