2015-09-04 41 views
0

我有一个DNS数据包类,看起来像这样(我粘贴只是其中的一部分):反序列化一个DNS包对象在C++ 11

class DNSPacket { 

public: 
    struct DNSHeader { 
     unsigned int ID :16; 
     unsigned int QR :1; 
     unsigned int OPCODE :4; 
     unsigned int AA :1; 
     unsigned int TC :1; 
     unsigned int RD :1;  
     unsigned int RA :1; 
     unsigned int Z :3; 

     unsigned int RCODE :4; 
     unsigned int QDCOUNT :16; 
     unsigned int ANCOUNT :16; 
     unsigned int NSCOUNT :16; 
     unsigned int ARCOUNT :16; 
    }; 

private: 
    DNSHeader header; 
    std::vector<DNSQuestion> questions; 
    std::vector<DNSAnswer> answers; 
    std::vector<DNSAnswer> nameservers; // TODO: DNSAnswer? 
    std::vector<DNSAnswer> add_records; // TODO: DNSAnswer? 
} 

什么是反序列化char的正确方法数组到这个对象?我有的选项是:重载>>运算符,添加一个单独的类以反序列化它以读取并反序列化字节后的数据读取字节并使用reinterpret_cast()

我想在C++ 11中创建一个快速,现代的实现。我应该选择哪种方式?另外,我应该如何反序列化位域 - 我应该坚持按位运算吗?

+1

char数组的格式是什么? – Surt

+0

这是一个封装了一些(问题或答案)DNS数据包的UDP数据帧。 – syntagma

+0

您的结构是错误的,根据[this](http://www.comptechdoc.org/independent/networking/terms/dns-message-format.html),“Z”字段是三位。 –

回答

1

我会这样做的方式是将字2(位16至31)视为单个无符号的16位整数(例如uint16_t),并通过使用按位AND和SHIFT操作来简单地获取位。所有其他字都可以用相同的方式读取,但是按原样使用或多或少(当然,从网络字节顺序转换为主机字节顺序后)。

为了让字X字作为uint16_t你必须做一些铸造:

uint16_t wordX = *reinterpret_cast<uint16_t*>(&your_array[X]); 

注意,对于第二个字,因为他们真的只是位,他们是按照指定的顺序,没有字节顺序转换在他们身上完成。

+0

endianness怎么样? Thete并没有说明他正在从事哪个平台。 – marom

+0

@marom除非RFC另有说明,否则长度超过8位的字应始终采用网络字节顺序,无论协议如何。 –

+0

这对于来自网络的数据来说是正确的,但是现在的大多数平台都是小端的,所以对于16位字应该有字节反转。 uint16_t wordX =(your_array [X] << 8)+ your_array [X + 1] – marom