Decouple packet reception logic in boost::asio
16:35 26 Aug 2026

A while back, I asked a question about receiving datagrams in batches using asio. Since, as it turns out, I can't do that, I have another question: Is it possible to decouple the packet reception from the socket creation logic in asio?

I'm still using the same server from my previous question. Let's take a look at the most important part receiving messages:

  // main receive function
  void do_receive()
  {
    socket_.async_receive_from(
        asio::buffer(data_, max_length), sender_endpoint_,
        [this](std::error_code ec, std::size_t bytes_recvd)
        {
          if (ec == asio::error::operation_aborted)
            return;

          if (ec)
            std::cerr << "error recv: " << ec.message() << '\n';
          else if (bytes_recvd > 0)
            handle(bytes_recvd);

          // receive more
          do_receive();
        });
  }

We have a call to the async_receive_from function, one of whose arguments is a lambda function (our completion handler). The problem with this code is that it’s essentially isolated. Inside the completion handler, we call this function again. And we continue receiving messages. I'd like to have code something like this:

// Our UDP server 
class UdpServer {
    // ctor && dctor && other methods like join_multicast

private:
    asio::io_context        m_ctx; // todo: or better to store it outside of server? 
    asio::ip::idp::socket   m_sock;
}



// Another place in my code
class AnotherPlace {
    // every time UdpServer received new packet this function is called
    void packet_received(Packet& packet) {

    }
}

Is that possible? We now have a completely separate area for receiving packets and can process them there. We no longer process them directly on the server, which I consider bad practice, because the server shouldn't be parsing packets.

c++ network-programming asio