我们在内存中使用直接叠加在二进制数据包上的打包结构,我正在决定做这件事的那一天。我们已经得到了这个工作的唯一方法是:
- 仔细定义位宽根据编译环境的具体类型(
typedef unsigned int uint32_t
)
- 中插入相应的特定于编译器的编译指定的紧密堆积结构成员
- 要求一切都在一个字节顺序(使用网络或大端排序)
- 精心编写服务器和客户端代码
如果您刚刚开始,我会建议您跳过试图用结构表示线路上的内容。只需分别序列化每个基元。如果您选择不使用像Boost Serialize这样的现有库或者像TibCo这样的中间件,那么可以通过在隐藏序列化方法细节的二进制缓冲区周围编写一个抽象来节省您很多头痛的问题。瞄准像一个接口:
class ByteBuffer {
public:
ByteBuffer(uint8_t *bytes, size_t numBytes) {
buffer_.assign(&bytes[0], &bytes[numBytes]);
}
void encode8Bits(uint8_t n);
void encode16Bits(uint16_t n);
//...
void overwrite8BitsAt(unsigned offset, uint8_t n);
void overwrite16BitsAt(unsigned offset, uint16_t n);
//...
void encodeString(std::string const& s);
void encodeString(std::wstring const& s);
uint8_t decode8BitsFrom(unsigned offset) const;
uint16_t decode16BitsFrom(unsigned offset) const;
//...
private:
std::vector<uint8_t> buffer_;
};
的每个包类必须序列化到一个ByteBuffer
或者从ByteBuffer
和反序列化偏移的方法。这是我绝对希望我能够及时回到正确的那些东西之一。我无法计算我花费时间调试由于忘记交换字节或未包装struct
而导致的问题的次数。
要避免的另一个陷阱是使用union
来表示字节或memcpy
ing到unsigned char缓冲区以提取字节。如果你总是在电线上使用大端,然后就可以用简单的代码来写字节的缓冲区,而不是担心htonl
东西:
void ByteBuffer::encode8Bits(uint8_t n) {
buffer_.push_back(n);
}
void ByteBuffer::encode16Bits(uint16_t n) {
encode8Bits(uint8_t((n & 0xff00) >> 8));
encode8Bits(uint8_t((n & 0x00ff) ));
}
void ByteBuffer::encode32Bits(uint32_t n) {
encode16Bits(uint16_t((n & 0xffff0000) >> 16));
encode16Bits(uint16_t((n & 0x0000ffff) ));
}
void ByteBuffer::encode64Bits(uint64_t n) {
encode32Bits(uint32_t((n & 0xffffffff00000000) >> 32));
encode32Bits(uint32_t((n & 0x00000000ffffffff) ));
}
这很好地保留了平台无关的,因为数字表示始终逻辑上大端。这段代码也非常适合使用基于原始类型大小的模板(想想encode<sizeof(val)>((unsigned char const*)&val)
)......不是很漂亮,但是非常容易编写和维护。
这是一个有趣的帖子,关于网络程序员应该知道的东西 - http://stackoverflow.com/questions/366257/everything-ac-developer-should-know-about-network-programming – zooropa 2009-04-16 15:17:13