I am writing a Server application on boost::asio
- Here I instantiate a
Server
that owns anio_service
- Server is started by
server.start()
method which callsServer::accept()
and that creates a newSession
even before it gets a new connection - Calls
_acceptor.async_accept
thats set a callback that callsSession::handler()
method which does the handshaking.
Now is it okay to create a socket even before getting a new client ?
and in this code the Session is auto destructed after writing an "Hello "
Message which is Okay in case of HTTP, But I want to carry on a Stateful Communication. so socket must async_wait
for reading after it just wrote this "Hallo "
. also I'd like to know whether this design is okay ? or it Has any design flaw.
Here goes My Compilable Code
~
class Session: public boost::enable_shared_from_this<Session>, private boost::noncopyable{
private:
size_t _id;
boost::asio::ip::tcp::socket _socket;
public:
typedef boost::shared_ptr<Session> pointer;
static pointer create(boost::asio::io_service& ios){
return pointer(new Session(ios));
}
private:
explicit Session(boost::asio::io_service& ios): _socket(ios){
static size_t counter = 0;
_id = counter++;
std::cout << ">> Session " << id() << " constructing" << std::endl;
}
public:
void handler(const boost::system::error_code &ec){
const std::string message = (boost::format("HTTP/1.1 200 OK\r\nContent-Length: %2%\r\n\r\nHello, %1%!") % id() % (7+boost::lexical_cast<std::string>(id()).length())).str();
if(!ec){
boost::asio::async_write(_socket, boost::asio::buffer(message), boost::bind(&Session::write_handler, this));
}else{
std::cout << ec.message() << std::endl;
}
}
void write_handler(){
}
size_t id() const{
return _id;
}
boost::asio::ip::tcp::socket& socket(){
return _socket;
}
virtual ~Session(){
std::cout << ">> Session " << id() << " destructing" << std::endl;
}
};
class Server: public boost::enable_shared_from_this<Server>, private boost::noncopyable{
private:
boost::asio::io_service _ios;
boost::asio::ip::tcp::acceptor _acceptor;
public:
explicit Server(boost::asio::ip::tcp::endpoint& endpoint):_acceptor(_ios, endpoint){
}
void start(){
accept();
_ios.run();
}
void accept(){
std::cout << "accepting " << std::endl;;
Session::pointer session = Session::create(_ios);
_acceptor.async_accept(session->socket(), boost::bind(&Server::handler, this, session, boost::asio::placeholders::error));
}
void handler(Session::pointer session, const boost::system::error_code &ec){
if(!ec){
session->handler(ec);
}else{
//possible destroy session ? but how to destroy a shared pointer ?
}
accept();
}
};
int main(){
const unsigned int port = 5050;
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
Server server(endpoint);
server.start();
return 0;
}
The overall design looks okay, but there are a few implementation errors:
Session::handler()
:message
, the underlying buffer providedasync_write()
, may go out of scope beforeasync_write()
is invoked. This is a violation of the guarantee required by the API. Consider makingmessage
a member variable forSession
, or make itstatic
within the member function. This is the relevant excerpt from the documentation:Although the buffers object may be copied as necessary, ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called. Here is the relevant excerpt from the documentation:
For objects inheriting from
boost::enable_shared_from_this
, useshared_from_this()
instead of thethis
pointer when passing the instance handle toboost::bind
. Otherwise, it is possible that the object instance pointed to bythis
may be deleted prior to the handler running.
Also, to address the question in the code comment within the Server::handler()
, if an error occurs, the Session
will be deleted once the handler returns since it is managed via a boost::shared_ptr
.
来源:https://stackoverflow.com/questions/11021735/boost-asio-stateful-server-design