I have a setup that uses boost's serialization to archive objects to a file. I want/need to do the same but writing to POSIX pipes instead of basic files.
A simple packet:
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include "AbstractPacket.hpp"
struct SimplePacket final: public AbstractPacket{
bool value;
BooleanPacket() noexcept = default;
template <typename Archive>
void serialize(Archive& a, const unsigned int) {
a& boost::serialization::base_object<AbstractPacket>(*this);
a& value;
}
~SimplePacket() = default;
};
Writing the simple packet:
#include "SimplePacket.hpp"
BOOST_CLASS_EXPORT_GUID(SimplePacket, "SimplePacket")
//...//
void write(Packet* packet){
std::ofstream file;
file.open(_client_pipe, std::fstream::out | std::fstream::binary);
if (file.is_open()) {
boost::archive::binary_oarchive oa(file);
oa << packet;
file.close();
}
}
This writes the packet (boost serialized archive) to the file. However, I need to write to posix pipes. I have read that using boost.iostream is it possible to open a file stream to a POSIX pipe from its file descriptor. I haven't found a clear way to do this; but I would like to do this without using boost.iostream, is such a thing possible, and if so how could I do it ?
Together, Boost Asio + Process can also do this:
size_t write(Packet* packet) {
boost::asio::streambuf sb;
{
std::ostream os(&sb);
boost::archive::binary_oarchive oa(os);
oa << packet;
}
boost::asio::io_context ctx;
boost::process::async_pipe p(ctx); // opens a pipe (pair of fds)
size_t bytes = write(p, sb); // throws system_error on error
return bytes;
}
If you already have the pipe, use the appropriate constructor for async_pipe
to pass the fds.
Also, if you already have the pipe fd, I'd suggest not using Boost Process at all:
boost::asio::io_context ctx;
boost::asio::posix::stream_descriptor s(ctx, 2); // STDERR
size_t bytes = write(s, sb); // throws system_error on error
s.release(); // to avoid close on destruction
In particular, note the release()
that might save you time scratching your head.
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
struct AbstractPacket {
virtual ~AbstractPacket() = default;
template <typename Archive> void serialize(Archive&, unsigned) {}
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(AbstractPacket)
struct BooleanPacket : public AbstractPacket {
bool value;
template <typename Archive> void serialize(Archive& a, unsigned) {
a& boost::serialization::base_object<AbstractPacket>(*this);
a& value;
}
};
BOOST_CLASS_EXPORT(BooleanPacket)
#include <boost/asio.hpp>
size_t write(AbstractPacket* packet) {
boost::asio::streambuf sb;
{
std::ostream os(&sb);
boost::archive::text_oarchive oa(os);
oa << packet;
}
boost::asio::io_context ctx;
boost::asio::posix::stream_descriptor s(ctx, 2); // STDERR
size_t bytes = write(s, sb); // throws system_error on error
s.release(); // to avoid close on destruction
return bytes;
}
#include <iostream>
int main() {
auto test = new BooleanPacket(); // please use smart pointers
test->value = true;
std::cout << "Bytes written: " << write(test) << "\n";
delete test; // please use smart pointers
}
Prints stderr:
22 serialization::archive 18 1 13 BooleanPacket 1 0
0 1 0
1 1
And stdout:
Bytes written: 62