简体   繁体   English

如何在不破坏数据的情况下将缓冲区投射到结构?

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

i am working on a network project of mine in order to learn more about networking and right now i have designed a simple protocol/structure that i fill and send to the server, the problem is that all vectors and probably arrays aswell are invalid on the server side. 我正在从事我的网络项目,以便更多地了解网络,现在我设计了一个简单的协议/结构,将其填充并发送到服务器,问题是所有矢量以及可能的数组在服务器端。

im gonna try to explain it with code, its alot easier that way. 我会尝试用代码来解释它,这样很容易。

My protocol: 我的协议:

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

so its a pretty simple protocol, and what i did is that i fill it with data and its completely valid on the client side, however as soon as i send it to the server and try to convert it back it the vector is invalid but the integers are still valid. 所以它是一个非常简单的协议,我所做的是我在客户端填充了数据并对其完全有效,但是,一旦我将其发送到服务器并尝试将其转换回向量,该向量是无效的,但是整数仍然有效。

this is how i create and send the data from the client: 这就是我从客户端创建和发送数据的方式:

NETWORK_PROTOCOL Protocol;

//Fills protocol with data

int sendt = send(ClientSocket, (const char*)&Protocol, Protocol.packet_size, 0);

and when it hits the server i still get the full size of the data, but as i said earlier it does not convert back properly :/ 当它到达服务器时,我仍然可以获得完整的数据大小,但是正如我之前所说,它不能正确转换回:/

Code on the server side that tries to cast it back: 尝试将其投射回服务器端的代码:

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 :/

im not really sure how to fix this problem, i thought it would be easy to convert it back since it is the exact same data on both sides. 我不是很确定如何解决这个问题,我认为将其转换回去很容易,因为双方的数据完全相同。 Any help to fix this issue is greatly appreciated. 感谢您提供任何解决此问题的帮助。

std::vector can't be transferred this way: internally it uses pointers, so you send only a pointer, without any actual information, and that pointer is not valid on the receiving side. std :: vector不能以这种方式传输:内部使用指针,因此您仅发送一个指针,而没有任何实际信息,并且该指针在接收端无效。

In order to send the contents of vector, you need to somehow serialize it (convert it to the representation in which it can be easily transferred). 为了发送向量的内容,您需要以某种方式对其进行序列化(将其转换为可以轻松传输的表示形式)。 For example, you can use is Boost.Serialization 例如,您可以使用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;
};

Now you can serialize it like this: 现在您可以像这样序列化它:

    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()

Deserialize it like this: 像这样反序列化:

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

For practical usages you may want to use binary archives instead. 对于实际用途,您可能需要使用二进制存档。 If you decide to go with boost.serialization, I recommend starting looking here . 如果您决定使用boost.serialization,建议您从此处开始。

You may also like Google Protocol Buffers: https://developers.google.com/protocol-buffers/docs/cpptutorial 您可能还喜欢Google协议缓冲区: https : //developers.google.com/protocol-buffers/docs/cpptutorial

This comment is longer than allowed. 此评论的长度超出了允许范围。 So I put it as an answer; 所以我把它作为答案。 although I think it answers partially. 尽管我认为它可以部分回答。

To send all the data in one shipment wasted space and bandwidth, because you'd have to take a maximum for the number of names and their sizes. 要一次发送所有数据,这将浪费空间和带宽,因为您必须使用最大数量的名称及其大小。 So I suggest you divide your transmission in phases. 因此,我建议您分阶段进行传输。

In the first phase you send the number of filenames that you are transmitting. 在第一个阶段中,您将发送正在传输的文件名数量。 In this way you prepare the server for receiving n file names. 通过这种方式,您可以准备服务器以接收n文件名。 Then in the second phase you make a loop divided in two transmissions. 然后在第二阶段中,将循环分成两个传输。 The first transmission you send the file name size, then you prepare a buffer for receiving the filename. 第一次发送时,您发送文件名的大小,然后准备一个缓冲区来接收文件名。

For these modes you only use basic types ( size_t and char * ). 对于这些模式,您仅使用基本类型( size_tchar * )。

On the server side you can build your vector<string> , if you want to give that illusion 在服务器端,如果您想给出这种错觉,则可以构建vector<string>

I hope it helps you 希望对您有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM