I'm creating a server using boost::asio::ip::tcp, but I'm having problems using streams to do this.
The design pattern I'm using is:
stream
object. Session
object is created. The stream object is passed to the Session
, then we repeat step 2 with a new iostream object. The code looks like this:
class Session; // Ctor: Session(asio::ip::tcp::stream tcp_stream)
class Server
{
public:
Server(boost::asio::io_service& p_service, unsigned p_port) :
m_service(p_service),
m_acc(m_service, boost::asio::ip::tcp::endpoint( asio::ip::tcp::v4(), p_port ) )
{
m_acc.async_accept(
*m_tcp_stream.rdbuf(),
std::bind(&Server::AcceptHandler, this, _1)
);
}
private:
void AcceptHandler(const boost::system::error_code& p_error)
{
if( !p_error )
{
boost::asio::ip::tcp::iostream tcp_stream;
std::swap(m_tcp_stream, tcp_stream);
new Session( std::move(tcp_stream) );
m_acc.async_accept(
*m_tcp_stream.rdbuf(),
std::bind(&Server::AcceptHandler, this, _1)
);
}
}
private:
boost::asio::io_service& m_service;
boost::asio::ip::tcp::iostream m_tcp_stream;
boost::asio::ip::tcp::acceptor m_acc;
};
My problem is that boost::asio::ip::tcp::iostream
has no move ctor. This prevents the std::swap()
or new Session()
lines from compiling.
I could use this pattern with boost::asio::ip::tcp::socket because it supports the move ctor, but for some reason, streams don't support it. If I could extract a stream from a socket, then I'd be able to work around this, but I can't figure out how to do that.
What's the best way to accept TCP streams and pass the connections to objects which handle sessions?
Just wrap your session in a shared pointer: std::shared_ptr<Session>
and keep it prepared for acceptor. Once the connection is instantiated initiate its life-circle. See ASIO example: http://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp. There is also session class in it.
class Server
{
public:
Server(boost::asio::io_service& p_service, unsigned p_port) :
m_service(p_service),
m_acc(m_service, boost::asio::ip::tcp::endpoint( asio::ip::tcp::v4(), p_port ) ),
m_session( std::make_shared< Session >() )
{
StartListen();
}
private:
void StartListen()
{
m_acc.async_accept(
m_session->tcp_stream().rdbuf(),
std::bind(&Server::AcceptHandler, this, _1) );
}
void AcceptHandler(const boost::system::error_code& p_error)
{
if( !p_error )
{
auto ses = std::make_shared< Session >();
std::swap( ses, m_session );
ses->InitLifeCircle(); // Start whatever logic you needed.
StartListen();
}
}
private:
boost::asio::io_service& m_service;
boost::asio::ip::tcp::acceptor m_acc;
std::shared_ptr< Session > m_session;
};
Also you can use the latest boost (1.66). It supports move constructor for boost::asio::ip::tcp::iostream
http://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/ip__tcp/iostream.html.