0

これは私のboost::asioサーバーです

class Server: public boost::enable_shared_from_this<Server>, private boost::noncopyable{
  private:
    boost::asio::ip::tcp::acceptor _acceptor;
    boost::asio::ip::tcp::socket   _socket;
  public:
    explicit Server(boost::asio::io_service& ios, boost::asio::ip::tcp::endpoint& endpoint):_acceptor(ios, endpoint), _socket(ios){

    }
    void start(){
       accept();
    }
    void accept(){
       std::cout << "accepting " << std::endl;;
      _acceptor.async_accept(_socket, boost::bind(&Server::handler, this, boost::asio::placeholders::error));
    }
    void handler(const boost::system::error_code &ec){
       const std::string message = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!";
       if(!ec){
         boost::asio::async_write(_socket, boost::asio::buffer(message), boost::bind(&Server::write_handler, this));
       }else{
         std::cout << ec << std::endl;
       }
       accept();
    }
    void write_handler(){

    }
    boost::asio::ip::tcp::socket& socket(){
      return _socket;
    }
};


int main(){
  boost::asio::io_service ios;
  const unsigned int port = 5050;
  boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);

  Server server(ios, endpoint);
  server.start();

  ios.run();
  return 0;
}

初めて「HalloWorld」で応答します。次に、accept<->handlerループでループし続け、ウェルカムメッセージを書き込みません。ecプリント

asio.misc:1
accepting 
asio.misc:1
accepting 
asio.misc:1
accepting 
asio.misc:1
accepting 
asio.misc:1
accepting 
asio.misc:1
accepting 
......

そして決して止まらない

4

1 に答える 1

4

無限ループは、_socket使用中の結果です。最初は使用されていないasync_accept()ため動作_socketします。ただし、_socketは閉じられないため、async_accept()withへの追加の呼び出し_socketは失敗します。のpeer引数は、新しい接続にソケットを使用するため、ソケットが使用されていないことを想定していますasync_accept()。これは、次のいずれかで解決できます。

  • 接続ごとに新しいソケットを割り当てます。を介してソケットを管理することを検討してくださいboost::shared_ptr。これにより、サーバーは複数の同時接続を処理できます。
  • を閉じて_socketからwrite_handler、を呼び出しaccept()ます。これにより、サーバーは一度に1つの接続に制限されます。

また、に注意してasync_write()ください。基になるバッファメモリの所有権は呼び出し元によって保持されます。呼び出し元は、ハンドラが呼び出されるまで有効なままであることを保証する必要があります。この場合、は呼び出されるmessage前にスタックからポップオフします。write_handler()messageあると、その期間を保証するためにそれをconst作ることを検討してください。static

オブジェクトをインスタンスに渡して呼び出しを行う場合は、shared_from_this()代わりに使用してください。そうしないと、参照カウントが適切に行われるのは。を使用する場合のみであるため、が指すインスタンスが削除される可能性があります。thisbindthisshared_from_this()

最後に、印刷するときは、このメソッドをboost::system::error_code使用してerror_code.message()、より意味のあるメッセージを取得します。無限ループの場合、「すでに開いています」と出力されます。

一度に1つの接続をサポートする変更されたhandler()コードwrite_handler()は次のとおりです。

void accept(){
   std::cout << "accepting " << std::endl;;
  _acceptor.async_accept(_socket, boost::bind(&Server::handler, shared_from_this(), boost::asio::placeholders::error));
}
void handler(const boost::system::error_code &ec){
   // Guarantee message will remain valid throughout the duration of async_write.
   static const std::string message = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!";
   if(!ec){
     // write_handler will accept the next connection once it is done with the socket.
     boost::asio::async_write(_socket, boost::asio::buffer(message), boost::bind(&Server::write_handler, shared_from_this()));
   }else{
     std::cout << ec.message() << std::endl;
     // Try accepting on error.
     accept();
   }
}
void write_handler(){
   _socket.close();
   // Now that the socket is closed, new connectiosn can be accepted.
   accept();
}
于 2012-06-13T13:06:13.180 に答える