Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost ASIO UDP client async_receive_from calls handler even when there are no incoming messages

I've modified the UDP client code from Boost daytime client tutorial into the following:

class UDPClient
{
public:
    udp::socket* socket;
    udp::endpoint* receiver_endpoint;
    boost::array<char, 1024> recv_buffer;

    UDPClient();
    void do_receive();
    void handle_receive(const boost::system::error_code& error, size_t);
};

UDPClient::UDPClient()
{
    boost::asio::io_service io_service;

    udp::resolver resolver(io_service);
    udp::resolver::query query(udp::v4(), "127.0.0.1", "8888");
    receiver_endpoint = new udp::endpoint(*resolver.resolve(query));

    socket = new udp::socket(io_service);
    socket->open(udp::v4());

    do_receive();

    while (true)
    {
        io_service.poll();
        Sleep(1);
    }
}

void UDPClient::do_receive()
{
    socket->async_receive_from(boost::asio::buffer(recv_buffer), *receiver_endpoint,
                               boost::bind(&UDPClient::handle_receive, this,
                               boost::asio::placeholders::error,
                               boost::asio::placeholders::bytes_transferred));
}

void UDPClient::handle_receive(const boost::system::error_code& error, size_t bytes_transferred)
{
    cout << "ulala" << endl;

    if (!error || error == boost::asio::error::message_size)
        do_receive();
}

If all works out according to plan, "ulala" would only be printed if there is an incoming message. However that is not the case here... The handler gets called instantaneously and "ulala" is printed regardless of whether there is an incoming message. I've tried a few different things: swapping io_service.poll() with io_service.run() and io_service.run_one(), as well as removing Sleep(1), but none of those changes have any effect on the problem. What should I do?

Thanks in advance!

like image 828
Lai Xue Avatar asked Aug 31 '25 18:08

Lai Xue


1 Answers

socket = new udp::socket(io_service);
socket->open(udp::v4());

sets up a socket for sending to arbitrary endpoints. To receive ("listen"), use

socket = new udp::socket(io_service, udp::endpoint(udp::v4(), 8888));

Besides that, the socket and receiver_endpoint are leaked now. To fix that:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <iostream>

using boost::asio::ip::udp;

class UDPClient
{
public:
    boost::asio::io_service io_service;
    udp::socket socket;
    udp::endpoint receiver_endpoint;
    boost::array<char, 1024> recv_buffer;

    UDPClient();
    void do_receive();
    void handle_receive(const boost::system::error_code& error, size_t);
};

UDPClient::UDPClient()
    : io_service(),
      socket(io_service, {udp::v4(), 8888})
{
    do_receive();
    io_service.run();
}

void UDPClient::do_receive()
{
    socket.async_receive_from(boost::asio::buffer(recv_buffer), receiver_endpoint,
                               boost::bind(&UDPClient::handle_receive, this,
                               boost::asio::placeholders::error,
                               boost::asio::placeholders::bytes_transferred));
}

void UDPClient::handle_receive(const boost::system::error_code& error, size_t bytes_transferred)
{
    std::cout << "ulala" << std::endl;
    std::cout << "Received: '" << std::string(recv_buffer.begin(), recv_buffer.begin()+bytes_transferred) << "'\n";

    if (!error || error == boost::asio::error::message_size)
        do_receive();
}

int main()
{
    UDPClient updclient;
}

This also prints the message received (assuming it is printable). See

  • boost::asio async_receive_from UDP endpoint shared between threads?

for a way to make it possible to handle multiple UDP requests concurrently.

like image 102
sehe Avatar answered Sep 02 '25 08:09

sehe