3

サーバーアプリケーションを書いていますboost::asio

  1. Serverここでは、を所有するをインスタンス化します。io_service
  2. サーバーは、新しい接続を取得する前であってもserver.start()、呼び出しServer::accept()て新しいを作成するメソッドによって起動されますSession
  3. ハンドシェイクを行うメソッドを呼び出すコール_acceptor.async_acceptバックを設定する呼び出しSession::handler()

新しいクライアントを取得する前にソケットを作成しても問題ありませんか? このコードでは、HTTP の場合は OK であるメッセージを書いた後にセッションが自動的に破棄され"Hello "ますが、ステートフル通信を続けたいと考えています。そのため、ソケット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;
}
4

1 に答える 1

3

全体的な設計は問題ないように見えますが、いくつかの実装エラーがあります。

  • Session::handler():が呼び出される前messageに、基礎となるバッファが提供さasync_write()れ、範囲外になる場合があります。async_write()これは、API が要求する保証に違反しています。messageのメンバー変数を作成するSessionstatic、メンバー関数内で作成することを検討してください。これは、ドキュメントからの関連する抜粋です。

    buffers オブジェクトは必要に応じてコピーできますが、基になるメモリ ブロックの所有権は呼び出し元によって保持されます。呼び出し元は、ハンドラーが呼び出されるまでそれらが有効であることを保証する必要があります。ドキュメントからの関連する抜粋は次のとおりです。

  • から継承するオブジェクトの場合、インスタンス ハンドルを に渡すときにポインタの代わりにboost::enable_shared_from_this使用します。そうしないと、ハンドラーが実行される前に、 が指すオブジェクト インスタンスが削除される可能性があります。shared_from_this()thisboost::bindthis

また、 内のコード コメントの質問に対処するためにServer::handler()、 エラーが発生した場合、Sessionは 経由で管理されているため、ハンドラーが戻ると削除されますboost::shared_ptr

于 2012-06-13T21:10:38.293 に答える