boost::asio acceptor reopen and async read after EOF

吃可爱长大的小学妹 提交于 2020-03-06 03:55:27

问题


sadly I've come to a hold in my development since I can not understand how exactly the boost::asio::ip::tcp::acceptor is supposed to be used. The TCPReader class is designed to be a singleton and the header declares the following as private.

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();
}

the accept_handler than triggers the read_handler and it all works like a charm until the read_handler receives EOF or another error. What I want is to get the acceptor back into a state where it can accept connections like it did after initialization. I tried close() or cancel() with a following open() , listen() and async_accept(like in the constructor). But it all does not seem to work. Very much would appreciate your help.


回答1:


The error is occurring in an operation on sock, not acceptor. Thus, acceptor's state should not be affected. It just requires initiating an async_accept operation with sock being in its initial closed state.

Here is a complete basic example that listens on port 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();
}

When using it, I ran it in one terminal, and connected to port 12345, send messages, killed connection, then reestablished a connection. The server console output was as follows:

[twsansbury@localhost]$ ./a.out 
accepting connection
reading from socket
hello
reading from socket
goodbye
reading from socket
handle_read: End of file
accepting connection
reading from socket
oh, oh no
reading from socket
handle_read: End of file
accepting connection
ctrl + c

and the client console:

[twsansbury@localhost]$ nc 127.0.0.1 12345
hello        
goodbye 
ctrl + c
[twsansbury@localhost]$ nc 127.0.0.1 12345
oh, oh no
ctrl + c

One behavioral detail of which to be aware is that although an async_accept operation may not be pending on the acceptor_, connections are still being queued. Thus, if a connection has already been accepted, and another client tries to connect, then the latter client will have its connection pending to be accepted. If this is not the desired behavior, then the acceptor needs to transition out of a listening state via close(). This answer diagrams state transitions and describes some of the acceptor behavior in more detail.



来源:https://stackoverflow.com/questions/15926077/boostasio-acceptor-reopen-and-async-read-after-eof

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!