Я делаю что-то вроде этого (довольно непроверенного) кода:
Код библиотеки:
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
и отправляя их отдельно.Например, std::string
можно отправить как std::size_t
для длины, а остальные как массив символов .