0

I got this code online and have been trying to add a timer to it so that it reads a packet every so often. I can't seem to figure out how to pass a callback function to the boost::async_wait command because I am getting this error:

server1.cpp: In member function ‘void UDPClient::handle_receive(const boost::system::error_code&, size_t)’:
server1.cpp:51:66: error: invalid use of non-static member function ‘void UDPClient::time_to_receive(const boost::system::error_code&)’
                                  boost::asio::placeholders::error));
                                                                  ^
server1.cpp:33:6: note: declared here
 void UDPClient::time_to_receive(const boost::system::error_code& error)
      ^~~~~~~~~

UDPClient Class:

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

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

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

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

UDPClient::UDPClient()
    : io_service(),
      socket(io_service, {udp::v4(), 3643}),
      timer(io_service, boost::posix_time::seconds(2))
{
    do_receive();
    io_service.run();
}

void UDPClient::time_to_receive(const boost::system::error_code& error)
{
    do_receive();
}

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 << "Received: '" << std::string(recv_buffer.begin(), recv_buffer.begin()+bytes_transferred) << "'\n";

    timer.async_wait(boost::bind(time_to_receive,
                                 boost::asio::placeholders::error));
}

int main()
{
    UDPClient updclient;
}

One question I'm trying to answer with this code is if I spam the server from a client with a bunch of UDP packets will the server ignore all the packets during the async_wait?

Also, my main goal is to put this code into a quadcopter code I have. Will it work the way it is written to instantiate this class and have it read packets from a ground station to get user input?

Arunmu
  • 6,837
  • 1
  • 24
  • 46
minnymauer
  • 374
  • 1
  • 4
  • 17

1 Answers1

2

The way you use bind with member function is wrong. Use it like shown below:

timer.async_wait(boost::bind(&UDPClient::time_to_receive, this,
                             boost::asio::placeholders::error));

As to why it is like that, I would recommend you to read the boost docs for that.

Also, I have modified the code to make it actually run like a server without exiting. For that I made following 2 changes:

  1. Initialzation of io_service in main function and pass its reference to the class.
  2. Initialize a io_service_work object. This acts as a perennial source of work to the io_service. Thus, io_service never returns from the run function unless the work object is destroyed.

The complete source:

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

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

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

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

UDPClient::UDPClient(boost::asio::io_service& ios)
    : io_service(ios),
      socket(io_service, {udp::v4(), 3643}),
      timer(io_service, boost::posix_time::seconds(2))
{
    do_receive();
}

void UDPClient::time_to_receive(const boost::system::error_code& error)
{
    do_receive();
}

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 << "Received: '" << std::string(recv_buffer.begin(), recv_buffer.begin()+bytes_transferred) << "'\n";
    timer.expires_from_now(boost::posix_time::seconds(2));
    timer.async_wait(boost::bind(&UDPClient::time_to_receive, this,
                                 boost::asio::placeholders::error));
}

int main()
{
  boost::asio::io_service ios;
  boost::asio::io_service::work wrk(ios);
  UDPClient updclient(ios);
  ios.run();
}

NOTE: Even though it is a server, the class is name Client. I am ignoring that :)

Arunmu
  • 6,837
  • 1
  • 24
  • 46
  • Wow, thanks for the note. I didn't even realize that haha. As for the updates, I actually can compile so thank you. I am, however, having a new issue in that the async_wait is not causing the server to wait 2 seconds. I'm spamming the server with many messages and it's receiving every message with no delay in between receives. – minnymauer Dec 15 '16 at 08:17
  • Oh, ok I get it. The async_wait cancels the timer after 2 seconds so you have to call expires_from_now? – minnymauer Dec 15 '16 at 16:23
  • Now that it's working I tested what happens if I spam the server from a client with UDP packets. Even though I'm calling async_receive_from every 2 seconds it is still getting every single packet. So it's lagging way behind. Is it possible to ignore all the packets between async_receive_from calls? – minnymauer Dec 15 '16 at 16:25
  • It appears this solved my previous question. [http://stackoverflow.com/a/2770714/3884880]. They suggested setting receive_buffer_size option to 0 like so. [http://www.boost.org/doc/libs/1_37_0/doc/html/boost_asio/reference/basic_datagram_socket/receive_buffer_size.html]. Appear to work as intended. – minnymauer Dec 15 '16 at 16:32