2012-06-13 145 views
3

我寫上boost::asio升壓ASIO狀態服務器設計

  1. 在這裏,我實例化一個Server擁有一個io_service
  2. 服務器由server.start()方法,它調用Server::accept()啓動服務器應用程序,並創建一個新的Session甚至在它得到一個新的連接
  3. 呼叫_acceptor.async_accept這就是設置調用Session::handler()方法能源部回調握手。

現在可以在獲得新客戶端之前創建套接字嗎? ,並且在這段代碼中,在編寫了一個"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; 
} 

回答

3

整體設計看起來不錯,但也有少數實現錯誤:

  • Session::handler()message,基礎緩衝區提供async_write(),可能會在調用async_write()之前超出範圍。這違反了API所要求的保證。考慮使message成員變量爲Session,或在成員函數中使其成爲static。這是從文檔的相關摘錄:

    雖然可以根據需要複製緩衝區對象,底層的內存塊的所有權由調用者,後者必須保證它們有效,直到處理程序被調用保留。下面是從文檔的相關摘錄:

  • 對於來自boost::enable_shared_from_this繼承對象,傳遞實例句柄boost::bind時使用shared_from_this()代替this指針。否則,可能會在處理程序運行之前刪除this指向的對象實例。

此外,爲了解決代碼註釋的問題Server::handler()內,如果發生錯誤,一旦處理程序返回,因爲它是通過boost::shared_ptr管理的Session將被刪除。

+0

謝謝。但是這個是無國籍的。它在一次寫入後破壞套接字。我想使它成爲有狀態的。怎麼樣 ? –

+0

取決於你想要完成的事情。只要共享指針通過排隊處理程序保持活動狀態,那麼'Session'及其套接字就不會被銷燬。例如,您可以使用['async_read'](http://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/reference/async_read/overload1.html)引入異步讀取循環。另外,請記住'HTTP'是一個無狀態協議;如果使用HTTP客戶端,可能會影響測試你的應用程序。 –

+0

那麼我會用'telnet'或套接字來測試。正如你所說的,我在'boost :: bind(&Server :: handler,shared_from_this(),session,boost :: asio :: placeholders :: error)''中用'shared_from_this()'替換了'this'',這給了我運行時錯誤'接受 >>會話0正在構建 終止在拋出'boost :: exception_detail :: clone_impl >' 實例後調用'':tr1 :: bad_weak_ptr 已中止# –