【问题标题】:boost::asio acceptor reopen and async read after EOFboost::asio 接受器在 EOF 之后重新打开和异步读取
【发布时间】:2013-04-10 12:38:19
【问题描述】:

遗憾的是,由于我无法理解 boost::asio::ip::tcp::acceptor 应该如何使用,因此我已经停止了开发。 TCPReader 类被设计为单例,并且标头将以下内容声明为私有。

void runInThread();

void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred);

void accept_handler(const boost::system::error_code &ec);

boost::asio::io_service io_service;
boost::asio::io_service::work runningService;
boost::asio::ip::tcp::socket sock;
boost::asio::ip::tcp::acceptor acceptor;

bool isConnected;

TCPReader::TCPReader() : sock(io_service),
                        runningService(io_service),
                        acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), TCPPort)){
    this->isConnected = false;

    acceptor.async_accept(sock, boost::bind(&TCPReader::accept_handler, this, boost::asio::placeholders::error));
    boost::thread thread(boost::bind(&TCPReader::runInThread, this));
}


 void TCPReader::runInThread(){
    io_service.run();
}

accept_handler 会触发 read_handler 并且在 read_handler 收到 EOF 或其他错误之前,这一切都像魅力一样工作。我想要的是让接受器恢复到它可以像初始化后那样接受连接的状态。我尝试了close() 或cancel() 以及以下open()、listen() 和async_accept(就像在构造函数中一样)。但这一切似乎都不起作用。 非常感谢您的帮助。

【问题讨论】:

    标签: c++ sockets boost c++11 boost-asio


    【解决方案1】:

    错误发生在sock 上的操作中,而不是acceptor。因此,acceptor 的状态不应受到影响。它只需要启动一个async_accept 操作,sock 处于其初始关闭状态。

    这是一个完整的基础示例,监听 12345 端口:

    #include <iostream>
    
    #include <boost/array.hpp>
    #include <boost/asio.hpp>
    
    using boost::asio::ip::tcp;
    
    class tcp_reader
    {
    public:
      tcp_reader(boost::asio::io_service& io_service)
        : io_service_(io_service),
          socket_(io_service),
          acceptor_(io_service, 
                    tcp::endpoint(tcp::v4(), 12345))
      {
        accept_connection();
      }
    
    private:
    
      void accept_connection()
      {
        std::cout << "accepting connection" << std::endl;
        // Verify socket is in a closed state.
        socket_.close();
        // On success or failure, acceptor will open() socket_.
        acceptor_.async_accept(socket_,
          boost::bind(&tcp_reader::handle_accept, this,
                      boost::asio::placeholders::error));
      }
    
      void handle_accept(const boost::system::error_code& error)
      {
        // On error, return early.
        if (error)
        {
          std::cout << "handle_accept: " << error.message() << std::endl;
          return;
        }
    
        // Start reading from socket.
        read();    
      }
    
      void read()
      {
        std::cout << "reading from socket" << std::endl;
        async_read(socket_, boost::asio::buffer(buffer_),
          boost::asio::transfer_at_least(1),
          boost::bind(&tcp_reader::handle_read, this,
                      boost::asio::placeholders::error,
                      boost::asio::placeholders::bytes_transferred));
      }
    
      void handle_read(const boost::system::error_code& error,
                       std::size_t bytes_transferred)
      {
        // On error, go back to listening for a new connection.
        if (error)
        {
          std::cout << "handle_read: " << error.message() << std::endl;
          accept_connection();
          return;
        }
    
        // Output read data.
        std::cout.write(&buffer_[0], bytes_transferred);
    
        // Read data, so read some more.
        read(); 
      }
    
    private:
      boost::asio::io_service& io_service_;
      tcp::socket              socket_;
      tcp::acceptor            acceptor_;
      boost::array<char, 1024> buffer_;
    };
    
    int main()
    {
      boost::asio::io_service io_service;
      tcp_reader reader(io_service);
      io_service.run();
    }
    

    使用的时候,我在一个终端上运行,连接到12345端口,发送消息,终止连接,然后重新建立连接。服务器控制台输出如下:

    [twsansbury@localhost]$ ./a.out
    接受连接
    从套接字读取
    你好
    从套接字读取
    再见
    从套接字读取
    handle_read:文件结束
    接受连接
    从套接字读取
    哦哦不
    从套接字读取
    handle_read:文件结束
    接受连接
    ctrl + c

    和客户端控制台:

    [twsansbury@localhost]$ nc 127.0.0.1 12345
    你好
    再见
    ctrl + c
    [twsansbury@localhost]$ nc 127.0.0.1 12345
    哦哦不
    ctrl + c

    需要注意的一个行为细节是,尽管async_accept 操作可能不会在acceptor_ 上挂起,但连接仍在排队。因此,如果一个连接已经被接受,并且另一个客户端尝试连接,那么后一个客户端将等待其连接被接受。如果这不是期望的行为,那么接受者需要通过close() 退出侦听状态。 This answer 图表状态转换并更详细地描述了一些接受器行为。

    【讨论】:

      猜你喜欢
      • 2011-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      • 2011-09-02
      相关资源
      最近更新 更多