C ++:使用缓冲区中的数据填充结构

时间:2018-10-22 01:33:49

标签: c++ struct dns buffer

我想知道我是否可以就如何从缓冲区中获取数据并将其加载到结构中提出一些建议。例如,我正在处理DNS响应缓冲区。我需要填充DNS答案结构,以便我可以解释数据。到目前为止,我有以下内容:

int DugHelp::getPacket() {
    memset(buf, 0, 2000); // clearing the buffer to make sure no "garbage" is there
    if (( n = read(sock, buf, 2000)) < 0 {
        exit(-1);
    }
    // trying to populate the DNS_Answers struct
    dnsAnswer = (struct DNS_Answer *) & buf;
    . . .
} 

这是我定义的结构:

struct DNS_Answer{
    unsigned char name [255];
    struct {
        unsigned short type;
        unsigned short _class;
        unsigned int ttl;
        unsigned in len;
    } types;
    unsigned char data [2000];
};

2 个答案:

答案 0 :(得分:1)

这取决于buf的数据格式。如果格式与DNS_Answer相同。您可以使用memcpy。如果它们的格式相同,则应先align the bytes

#pragma pack (1)
struct DNS_Answer{
    unsigned char name [255];
    struct {
        unsigned short type;
        unsigned short _class;
        unsigned int ttl;
        unsigned in len;
    } types;
    unsigned char data [2000];
};
#pragma pop(1)

然后

memcpy(dnsAnswer, buf, sizeof(DNS_Answer));

如果它们的数据格式不同,则必须自己解析它们,或者可以使用DFDL(一种数据格式描述语言)

答案 1 :(得分:0)

我做了一些类似以下(未经测试)的代码:

库代码:

namespace net {

using byte = unsigned char;

enum class endian
{
#ifdef _WIN32
    little = 0,
    big    = 1,
    native = little
#else
    little  = __ORDER_LITTLE_ENDIAN__,
    big     = __ORDER_BIG_ENDIAN__,
    native  = __BYTE_ORDER__,
#endif
};

constexpr bool is_little_endian()
{
    return endian::native == endian::little;
}

template<typename POD>
byte* write_to_buffer(POD const& pod, byte* pos)
{
    if(is_little_endian())
        std::reverse_copy((byte*)&pod, (byte*)& pod + sizeof(pod), pos);
    else
        std::copy((byte*)&pod, (byte*)& pod + sizeof(pod), pos);

    return pos + sizeof(pod);
}

template<typename POD>
byte const* read_from_buffer(byte const* pos, POD& pod)
{
    if(is_little_endian())
        std::copy(pos, pos + sizeof(pod), (byte*)&pod);
    else
        std::reverse_copy(pos, pos + sizeof(pod), (byte*)&pod);

    return pos + sizeof(pod);
}

} // namespace net

应用代码:

struct DNS_Answer{
    unsigned char name [255];
    struct {
        unsigned short type;
        unsigned short _class;
        unsigned int ttl;
        unsigned int len;
    } types;
    unsigned char data [2000];
};

net::byte* write_to_buffer(DNS_Answer const& ans, net::byte* buf)
{
    auto pos = buf;
    pos = net::write_to_buffer(ans.name, pos);
    pos = net::write_to_buffer(ans.types.type, pos);
    pos = net::write_to_buffer(ans.types._class, pos);
    pos = net::write_to_buffer(ans.types.ttl, pos);
    pos = net::write_to_buffer(ans.types.len, pos);
    pos = net::write_to_buffer(ans.data, pos);
    return pos;
}

net::byte const* read_from_buffer(net::byte const* buf, DNS_Answer& ans)
{
    auto pos = buf;
    pos = net::read_from_buffer(pos, ans.name);
    pos = net::read_from_buffer(pos, ans.types.type);
    pos = net::read_from_buffer(pos, ans.types._class);
    pos = net::read_from_buffer(pos, ans.types.ttl);
    pos = net::read_from_buffer(pos, ans.types.len);
    pos = net::read_from_buffer(pos, ans.data);

    return pos;
}

这应该是可移植的,处理不同的字节顺序,并避免潜在的对齐问题。您还可以通过将非Pod类型分解为几份POD并将它们分开发送来进行传输。例如,std::string可以作为std::size_t发送,而其余部分可以作为 char数组发送。