Reputation: 25708
In boost::asio standard examples after async_accept()
the socket
object is moving to the session
object (which handles all async_read()
calls) by initializing it as following:
std::make_shared<session>(std::move(socket_))->start();
And when constructing a session
it's moving again (isn't it reduntantly?):
session(tcp::socket socket)
: socket_(std::move(socket))
Then reading from a client is done as following:
boost::asio::async_read(socket_, ...
And all goes well. But when I trying to make async_read()
not from the session
object but directly from the async_accept()
and use it's socket
object, CPU is raising to 100% immediately after client connects. Why?
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class Server
{
public:
Server(boost::asio::io_service& io_service,
const tcp::endpoint& endpoint)
: acceptor_(io_service, endpoint),
socket_(io_service)
{
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec)
{
if (!ec) {
char* buf = new char[5];
boost::asio::async_read(socket_,
boost::asio::buffer(buf, 5),
[this, buf](boost::system::error_code ec, std::size_t)
{
if (!ec) {
std::cout.write(buf, 5);
std::cout << std::endl;
}
delete[] buf;
});
}
do_accept();
});
}
tcp::acceptor acceptor_;
tcp::socket socket_;
};
int main(int argc, char* argv[])
{
int port = 22222;
boost::asio::io_service io_service;
tcp::endpoint endpoint(tcp::v4(), port);
new Server(io_service, endpoint);
io_service.run();
}
Boost 1.49
EDIT
Thanks for the answers! I ended up by moving socket_
before using it:
tcp::socket *socket = new tcp::socket(std::move(socket_));
Also the same problem is discussed at Repeated std::move on an boost::asio socket object in C++11
Upvotes: 4
Views: 3174
Reputation: 51871
If the peer socket passed to basic_socket_acceptor::async_accept()
is not open, then it will be opened during the async_accept()
operation. Otherwise, if the peer is already open, then handler will be posted into the io_service
for invocation with an error code of boost::asio::error::already_open
. Hence, the posted code causes a tight asynchronous call chain to form:
async_accept()
operation is invoked the first time, causing socket_
to be opened.async_accept()
handler invokes do_accept()
, initiating an async_accept()
operation.socket_
is already open, causing the async_accept()
operation to post its handler into the io_service
with an error of boost::asio::error::already_open
.This behavior is not observed in the official examples because the socket's move operator causes the the moved-from object to be in the same state as if it was constructed using basic_stream_socket(io_service&)
constructor. Thus, the moved-from object is in a closed state, and ready for accepting.
Upvotes: 3
Reputation: 4241
You're using the single socket_
in all places, so when a connection is accepted, your handler calls do_accept() again which is using the same socket_
, then it's accepted again and again...
You probably need to always use a new socket like below:
void do_accept()
{
boost::shared_ptr<tcp::socket> psocket(new tcp::socket(io_service));
acceptor_.async_accept(*psocket, boost::bind(&Server::handleAccept, this, psocket, _1));
}
void handleAccept(boost::shared_ptr<tcp::socket> psocket, const boost::system::error_code& ec)
{
if (!ec) {
char* buf = new char[5];
boost::asio::async_read(
*psocket,
boost::asio::buffer(buf, 5),
[this, buf](boost::system::error_code ec, std::size_t)
{
if (!ec) {
std::cout.write(buf, 5);
std::cout << std::endl;
}
delete[] buf;
});
}
do_accept();
}
Upvotes: 1