Предложение
@ Guy (с использованием boost::asio::streambuf
) должно сработать, и его, вероятно, проще всего реализовать.Основным недостатком этого подхода является то, что все, что вы пишете в iostream, будет буферизироваться в памяти до конца, когда вызов boost::asio::write()
сбросит все содержимое буфера сразу в поток ssl.(Я должен отметить, что этот вид буферизации действительно может быть желателен во многих случаях, и в вашем случае это, вероятно, не имеет никакого значения, поскольку вы сказали, что это приложение с малым объемом).
Если это всего лишь "одноразовый", я бы, вероятно, реализовал его, используя подход @ Guy.
Как говорится, есть ряд веских причин, по которым вы могли бы иметьрешение, которое позволяет вам использовать вызовы iostream для записи прямо в ваш ssl_stream
.Если вы обнаружите, что это так, то вам нужно создать свой собственный класс-оболочку, который расширяет std::streambuf
, переопределяя overflow()
и sync()
(и, возможно, другие в зависимости от ваших потребностей).
К счастью, boost::iostreams
обеспечивает относительно простой способ сделать это без необходимости напрямую связываться с классами std.Вы просто создаете свой собственный класс, который реализует соответствующий Device
контракт.В этом случае это Sink
, и класс boost::iostreams::sink
предоставляется как удобный способ пройти большую часть пути туда.Когда у вас есть новый класс Sink, который инкапсулирует процесс записи в ваш базовый ssl_stream, все, что вам нужно сделать, это создать boost::iostreams::stream
, который настроен на ваш новый тип устройства, и все готово.
Itбудет выглядеть примерно так (этот пример адаптирован из здесь , см. также это сообщение о соответствующем стеке ):
//---this should be considered to be "pseudo-code",
//---it has not been tested, and probably won't even compile
//---
#include <boost/iostreams/concepts.hpp>
// other includes omitted for brevity ...
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_stream;
class ssl_iostream_sink : public sink {
public:
ssl_iostream_sink( ssl_stream *theStream )
{
stream = theStream;
}
std::streamsize write(const char* s, std::streamsize n)
{
// Write up to n characters to the underlying
// data sink into the buffer s, returning the
// number of characters written
boost::asio::write(*stream, boost::asio::buffer(s, n));
}
private:
ssl_stream *stream;
};
Теперь ваш цикл принятия может изменитьсячтобы выглядеть примерно так:
for(;;)
{
// Accept connection
ssl_stream stream(io_service, context);
tcp::endpoint peer_endpoint;
acceptor.accept(stream.lowest_layer(), peer_endpoint);
boost::system::error_code ec;
stream.handshake(boost::asio::ssl::stream_base::server, ec);
if (!ec) {
// wrap the ssl stream with iostream
ssl_iostream_sink my_sink(&stream);
boost::iostream::stream<ssl_iostream_sink> iostream_object(my_sink);
// Now it works the way you want...
iostream_object << HTTPReply(200, "Okely-Dokely\n") << std::flush;
}
}
Этот подход подключает поток ssl в инфраструктуру iostream.Так что теперь вы должны иметь возможность делать с iostream_object
в приведенном выше примере все, что вы обычно делаете с любым другим std::ostream
(например, stdout).И материал, который вы пишете, будет записан в ssl_stream за кулисами.Iostreams имеет встроенную буферизацию, поэтому некоторая степень буферизации будет происходить внутри - но это хорошо - он будет буферизироваться до тех пор, пока не накопит некоторое разумное количество данных, затем сбросит его в поток ssl, ивернуться к буферизации.Последний std :: flush, должен заставить его очистить буфер до ssl_stream.
Если вам нужен больший контроль над внутренней буферизацией (или другими дополнительными вещами), посмотритена другие интересные вещи, доступные в boost::iostreams
.В частности, вы можете начать с просмотра stream_buffer
.
Удачи!