提升asio有状态服务器设计

时间:2012-06-13 19:11:28

标签: c++ boost tcp boost-asio

我正在boost::asio

上编写一个服务器应用程序
  1. 此处我实例化拥有Server
  2. io_service
  3. 服务器由server.start()方法启动,该方法调用Server::accept()并在获得新连接之前创建新的Session
  4. 调用_acceptor.async_accept设置回调调用Session::handler()方法进行握手。
  5. 现在可以在获得新客户端之前创建套接字吗? 并且在此代码中,在写入"Hello "消息后会自动销毁会话,这在HTTP的情况下是好的,但我想继续进行有状态通信。所以套接字在写完async_wait之后必须"Hallo "才能阅读。我也想知道这个设计是否合适?或者它有任何设计缺陷。

    这是我的可编译代码

    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;
    }
    

1 个答案:

答案 0 :(得分:3)

总体设计看起来不错,但有一些实现错误:

  • Session::handler()message,提供async_write()的基础缓冲区可能会在调用async_write()之前超出范围。这违反了API所要求的保证。考虑将message设为Session的成员变量,或在成员函数中设为static。这是文档中的相关摘录:

      

    虽然可以根据需要复制buffers对象,但调用者保留底层内存块的所有权,这必须保证它们在调用处理程序之前保持有效。以下是文档中的相关摘录:

  • 对于从boost::enable_shared_from_this继承的对象,在将实例句柄传递给shared_from_this()时,请使用this而不是boost::bind指针。否则,可能会在处理程序运行之前删除this指向的对象实例。

另外,要解决Server::handler()中代码注释中的问题,如果发生错误,一旦处理程序返回,Session将被删除,因为它是通过boost::shared_ptr管理的