impulsar el diseño del servidor con estado asio

Estoy escribiendo una aplicación de servidor en boost::asio

  1. Aquí instanciamos un Server que posee un io_service
  2. El servidor se inicia con el método server.start() que llama a Server::accept() y que crea una nueva Session incluso antes de que obtenga una nueva conexión
  3. Las llamadas _acceptor.async_accept establecen una callback que llama al método Session::handler() que realiza el intercambio.

Ahora, ¿está bien crear un socket incluso antes de obtener un nuevo cliente? y en este código, la sesión se destruye automáticamente después de escribir un mensaje de "Hello " que está bien en el caso de HTTP, pero quiero llevar a cabo una comunicación de estado. así que socket debe async_wait para leer después de que acaba de escribir este "Hallo " . También me gustaría saber si este diseño está bien? o tiene algún defecto de diseño.

Aquí va mi código comstackble

~

 class Session: public boost::enable_shared_from_this, private boost::noncopyable{ private: size_t _id; boost::asio::ip::tcp::socket _socket; public: typedef boost::shared_ptr 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(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, 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 " <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; } 

El diseño general se ve bien, pero hay algunos errores de implementación:

  • Session::handler() : el message , el búfer subyacente proporcionado async_write() , puede salir del ámbito antes de que se async_write() . Esto es una violación de la garantía requerida por la API. Considere hacer que el message una variable miembro para Session , o hágalo static dentro de la función miembro. Este es el extracto relevante de la documentación:

    Aunque el objeto de búferes puede copiarse según sea necesario, el llamante conserva la propiedad de los bloques de memoria subyacentes, lo que debe garantizar que sigan siendo válidos hasta que se llame al controlador. Aquí está el extracto relevante de la documentación:

  • Para los objetos que heredan de boost::enable_shared_from_this , use shared_from_this() lugar del puntero de this cuando pase el identificador de instancia para boost::bind . De lo contrario, es posible que la instancia de objeto señalada por this pueda eliminarse antes de que se ejecute el controlador.

Además, para abordar la pregunta en el comentario de código dentro del Server::handler() , si ocurre un error, la Session se eliminará una vez que el manejador regrese, ya que se administra a través de un boost::shared_ptr .