boost :: asio无限循环

时间:2012-06-13 12:34:30

标签: boost boost-asio tcpserver

这是我的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;
}

第一次以'Hallo World'回应; 然后它只是在accept&lt; - &gt;中继续循环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 
......

永不停止

1 个答案:

答案 0 :(得分:4)

无限循环是_socket正在使用的结果。第一个async_accept()有效,因为_socket未使用。但是,_socket永远不会关闭,因此async_accept()_socket的额外调用将​​会失败。 async_accept() peer 参数期望套接字未被使用,因为它将使用套接字进行新连接。这可以通过以下任一方式解决:

  • 为每个连接分配一个新套接字。考虑通过boost::shared_ptr管理套接字。这允许服务器处理多个并发连接。
  • 关闭_socket中的write_handler,然后调用accept()。这会将服务器一次限制为一个连接。

另外,请注意async_write()。调用者保留底层缓冲区内存的所有权,调用者必须保证它在调用处理程序之前保持有效。在这种情况下,message将在调用write_handler()之前弹出堆栈。如果messageconst,请考虑将其static保证其持续时间。

在将对象传递给shared_from_this()调用的实例时,请使用this代替bind。否则,this指向的实例可能会被删除,因为只有在使用shared_from_this()时才能正确引用计数。

最后,在打印boost::system::error_code时,使用error_code.message()方法获取更有意义的消息。在无限循环的情况下,它将打印“已经打开”。

以下是一次支持一个连接的修改后的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();
}