问题
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