Michael IV
Michael IV

Reputation: 11424

asio async operations aren't processed

I am following ASIO's async_tcp_echo_server.cpp example to write a server.

My server logic looks like this (.cpp part):

1.Server startup:

bool Server::Start()
{
  mServerThread = std::thread(&Server::ServerThreadFunc, this, std::ref(ios));
  //ios is asio::io_service
}

2.Init acceptor and listen for incoming connection:

void Server::ServerThreadFunc(io_service& service)
{
    tcp::endpoint endp{ address::from_string(LOCAL_HOST),MY_PORT };
    mAcceptor = acceptor_ptr(new tcp::acceptor{ service,endp });
    // Add a job to start accepting connections.
    StartAccept(*mAcceptor);
    // Process event loop.Hang here till service terminated
    service.run();
    std::cout << "Server thread exiting." << std::endl;
}

3.Accept a connection and start reading from the client:

void Server::StartAccept(tcp::acceptor& acceptor)
{

    acceptor.async_accept([&](std::error_code err, tcp::socket socket)
    {
        if (!err)
        {
            std::make_shared<Connection>(std::move(socket))->StartRead(mCounter);
            StartAccept(acceptor);

        }
        else
        {
            std::cerr << "Error:" << "Failed to accept new connection" << err.message() << std::endl;
            return;
        }
    });

}

void Connection::StartRead(uint32_t frameIndex)
{
    asio::async_read(mSocket, asio::buffer(&mHeader, sizeof(XHeader)), std::bind(&Connection::ReadHandler, shared_from_this(), std::placeholders::_1, std::placeholders::_2, frameIndex));
}

So the Connection instance finally triggers ReadHandler callback where I perform actual read and write:

 void Connection::ReadHandler(const asio::error_code& error, size_t bytes_transfered, uint32_t frameIndex)
{

   if (bytes_transfered == sizeof(XHeader)) 
    {

            uint32_t reply;
            if (mHeader.code == 12345) 
            {
                reply = (uint32_t)12121;
                size_t len = asio::write(mSocket, asio::buffer(&reply, sizeof(uint32_t)));
            }
            else
            {
                reply = (uint32_t)0;
                size_t len = asio::write(mSocket, asio::buffer(&reply, sizeof(uint32_t)));
                this->mSocket.shutdown(tcp::socket::shutdown_both);
                return;
            }
    }

    while (mSocket.is_open())
    {
        XPacket packet;
        packet.dataSize = rt->buff.size();
        packet.data = rt->buff.data();
        std::vector<asio::const_buffer> buffers;
        buffers.push_back(asio::buffer(&packet.dataSize,sizeof(uint64_t)));
        buffers.push_back(asio::buffer(packet.data, packet.dataSize));

        auto self(shared_from_this());
        asio::async_write(mSocket, buffers,
            [this, self](const asio::error_code error, size_t bytes_transfered)
            {
                if (error)
                {
                     ERROR(200, "Error sending packet");
                     ERROR(200, error.message().c_str());
                }
            }
        );

    }


}

Now, here is the problem. The server receives data from the client and sends ,using sync asio::write, fine. But when it comes to to asio::async_read or asio::async_write inside the while loop, the method's lambda callback never gets triggered, unless I put io_context().run_one(); immediately after that. I don't understand why I see this behaviour. I do call io_service.run() right after acceptor init, so it blocks there till the server exit. The only difference of my code from the asio example, as far as I can tell, is that I run my logic from a custom thread.

Upvotes: 1

Views: 110

Answers (1)

Hasturkun
Hasturkun

Reputation: 36402

Your callback isn't returning, preventing the event loop from executing other handlers.

In general, if you want an asynchronous flow, you would chain callbacks e.g. callback checks is_open(), and if true calls async_write() with itself as the callback.

In either case, the callback returns.

This allows the event loop to run, calling your callback, and so on.

In short, you should make sure your asynchronous callbacks always return in a reasonable time frame.

Upvotes: 1

Related Questions