I want to send raw int
s with boost.asio compatibly with any CPU architecture. Usually, I would convert int
s to strings, but I may be able to get better performance by skipping the int
/ascii conversion. I don't know what boost.asio already does under the hood such as using htonl
. The documentation doesn't say and there is no way to test this code on my own PC.
Here are several methods I have to send an array of int
s over the network:
int
s in an array of int32_t
. Use htonl
and ntohl
to get correct endian-ness. If int32_t
is not supported on the target machine, handle that with int_fast32_t
and extra work.I think (1) is the "correct" alternative to non-ascii conversion. Can boost.asio or boost.serialization perform any of the steps of (1) for me? If not, what is the current recommended way to send int
s with boost.asio?
The other answer by @bazza has good professional advice. I won't repeat that. I get the impression you're more focusing on understanding the implementation specifics here, so I'll dive into the details of that for you here:
Yeah, option 1 seems okay for the simple use case you describe.
I don't know what boost.asio already does under the hood such as using htonl
It doesn't except perhaps in the protocol layers - but those are implementation details.
The documentation doesn't say
That's because it doesn't have an opinion on your application layer. The fact that it isn't mentioned is a good sign that no magic happens.
Can boost.asio or boost.serialization perform any of the steps of (1) for me?
Actually, no. The Boost binary archive is not portable (see also EOS Portable Archive).
Ironically, it can portably use one of the text archive formats https://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/archives.html#archive_models (XML and plain text are provided), but as you surmised they can have considerable overhead: Boost C++ Serialization overhead. Besides, there will be copying into and out of the stream format.
If not, what is the current recommended way to send ints with boost.asio?
I'd consider using the raw array/vector:
std::array<int32_t, 45> data;
boost::asio::async_write(socket_,
boost::asio::buffer(data),
...);
Of course you have to cater for endianness. Boost Endian has you covered in several ways. Compare the performance trade-offs here: https://www.boost.org/doc/libs/1_80_0/libs/endian/doc/html/endian.html#overview_performance
The simplest idea here is to use the drop-in (un)aligned arithmetic types:
std::array<boost::endian::big_int32_t, 45> data;
boost::asio::async_write(socket_,
boost::asio::buffer(data),
...);
To make the example a bit more life-like:
struct Message {
boost::endian::big_uint32_t magic = 0xCAFEBABE;
boost::endian::big_uint32_t length = 0;
std::vector<boost::endian::big_uint32_t> data;
std::array<boost::asio::const_buffer, 3> as_buffers() const {
length = data.length(); // update leading length header field
return {
boost::asio::buffer(&magic, sizeof(magic)),
boost::asio::buffer(&length, sizeof(length)),
boost::asio::buffer(data),
};
}
};
Now you can still:
Message message;
message.data = {1,2,3,4,5,6,7,8};
boost::asio::async_write(socket_,
message.as_buffers(),
...);