简体   繁体   中英

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!

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM