如何在不损坏数据的情况下将缓冲区强制转换为结构

How would one cast a buffer to a struct without corrupting the data?

本文关键字:缓冲区 转换 结构 情况下 损坏 数据      更新时间:2023-10-16

>我正在从事我的一个网络项目,以了解有关网络的更多信息,现在我已经设计了一个简单的协议/结构,我填充并发送到服务器,问题是所有向量和可能的数组在服务器端都是无效的。

我将尝试用代码解释它,这样要容易得多。

我的协议:

typedef struct NETWORK_PROTOCOL {
    int packet_size;
    int number_of_data_files;
    std::vector<std::string> data_files;
}

所以这是一个非常简单的协议,我所做的是我用数据填充它,它在客户端完全有效,但是一旦我将其发送到服务器并尝试将其转换回来,向量是无效的,但整数仍然有效。

这是我从客户端创建和发送数据的方式:

NETWORK_PROTOCOL Protocol;
//Fills protocol with data
int sendt = send(ClientSocket, (const char*)&Protocol, Protocol.packet_size, 0);

当它到达服务器时,我仍然会获得数据的完整大小,但正如我之前所说,它无法正确转换回来:/

服务器端尝试将其转换回的代码:

NETWORK_PROTOCOL* Protocol;
iResult = recv(ClientSocket, buffer, BUFFLEN, 0);
//then i have some validation code to check if the whole packet arrived since its TCP
Protocol = reinterpret_cast<NETWORK_PROTOCOL*>(buffer);
//And now the vector is invalid :/

我真的不确定如何解决这个问题,我认为很容易将其转换回来,因为它是双方完全相同的数据。非常感谢解决此问题的任何帮助。

std::vector 不能这样传输:在内部它使用指针,所以你只发送一个指针,没有任何实际信息,并且该指针在接收端无效。

为了发送 vector 的内容,您需要以某种方式对其进行序列化(将其转换为可以轻松传输的表示形式(。例如,您可以使用 Boost.Serialization

#include <sstream>
// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
struct NETWORK_PROTOCOL
{
private:
    friend class boost::serialization::access;
    // When the class Archive corresponds to an output archive, the
    // & operator is defined similar to <<.  Likewise, when the class Archive
    // is a type of input archive the & operator is defined similar to >>.
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & packet_size;
        ar & number_of_data_files; // you don't actually need it
        ar & data_files;
    }
public:
    int packet_size;
    int number_of_data_files;
    std::vector<std::string> data_files;
};

现在你可以像这样序列化它:

    std::ostringstream ofs;
    boost::archive::text_oarchive oa(ofs);
    oa << protocol; // protocol is your instance of NETWORK_PROTOCOL, which you want to send
   // and then you'll be able to get a buffer from ofs using ofs.str()

像这样反序列化它:

    NETWORK_PROTOCOL protocol;
    std::istringstream ifs(buf);
    boost::archive::text_iarchive ia(ifs);
    ia >> protocol;

对于实际用途,您可能希望改用二进制存档。如果你决定使用boost.serialization,我建议你从这里开始寻找。

您可能还喜欢 Google Protocol Buffers: https://developers.google.com/protocol-buffers/docs/cpptutorial

此注释比允许的要长。所以我把它作为一个答案;虽然我认为它部分回答。

在一次装运中发送所有数据浪费了空间和带宽,因为您必须对名称的数量及其大小进行最大限制。所以我建议你分阶段进行传输。

在第一阶段,您发送要传输的文件名数量。通过这种方式,您可以准备服务器以接收n文件名。然后在第二阶段,你制作一个分为两个传输的回路。第一次传输时,您发送文件名大小,然后准备用于接收文件名的缓冲区。

对于这些模式,您仅使用基本类型(size_tchar * (。

在服务器端,您可以构建vector<string>,如果您想给人这种错觉

希望对您有所帮助