C++, Boost - Best way to pass parameters to a function for TCP connection

Rocco Galati
Rocco Galati used Ask the Experts™
on
I'm using C++,  WxWdigets and Ubuntu and sometimes my application needs to send TCP packets to a TCP server.
The packets are in this format:
std::array<uint8_t, 8> command1;

Open in new window

I'm using a non-blocking TCP client method from boost asio and it works pretty well.
The problem is that I need to change the content of command1 since I need to send 32 different values depending on users actions.

At the moment, I connect to the server by using start_connection() function which connects to the server and execute the function start_write(int scelta) which sends the command1 over the net.

I would like to call the start_connection() function by passing the value of command1 in order to send it with start_write() function.
Is there any solution to do this?
Or, is there a smarter and faster solution to acquire what I need?

#include <boost/asio/buffer.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/write.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>

using boost::asio::steady_timer;
using boost::asio::ip::tcp;

std::array<uint8_t, 8> command1;

class client
{
public:
  client(boost::asio::io_context& io_context)
    : stopped_(false),
      socket_(io_context),
      deadline_(io_context),
      heartbeat_timer_(io_context)
  {
  }

 
  void start(tcp::resolver::results_type endpoints)
  {
    // Start the connect actor.
    endpoints_ = endpoints;
    start_connect(endpoints_.begin());

    deadline_.async_wait(boost::bind(&client::check_deadline, this));
  }

 
  void stop()
  {
    stopped_ = true;
    boost::system::error_code ignored_ec;
    socket_.close(ignored_ec);
    deadline_.cancel();
    heartbeat_timer_.cancel();
  }

private:
  void start_connect(tcp::resolver::results_type::iterator endpoint_iter)
  {
    if (endpoint_iter != endpoints_.end())
    {
      std::cout << "Trying " << endpoint_iter->endpoint() << "...\n";

      // Set a deadline for the connect operation.
      deadline_.expires_after(boost::asio::chrono::seconds(10));

      // Start the asynchronous connect operation.
      socket_.async_connect(endpoint_iter->endpoint(),
          boost::bind(&client::handle_connect,
            this, _1, endpoint_iter));
    }
    else
    {
      // There are no more endpoints to try. Shut down the client.
      stop();
    }
  }

  void handle_connect(const boost::system::error_code& ec,
      tcp::resolver::results_type::iterator endpoint_iter)
  {
    if (stopped_)
      return;

 
    if (!socket_.is_open())
    {
      std::cout << "Connect timed out\n";

      // Try the next available endpoint.
      start_connect(++endpoint_iter);
    }

    // Check if the connect operation failed before the deadline expired.
    else if (ec)
    {
      std::cout << "Connect error: " << ec.message() << "\n";

   
      socket_.close();

      // Try the next available endpoint.
      start_connect(++endpoint_iter);
    }

    // Otherwise we have successfully established a connection.
    else
    {
      std::cout << "Connected to " << endpoint_iter->endpoint() << "\n";

      // Start the heartbeat actor.
      start_write(1);
    }
  }

 

  void start_write(int scelta)
  {
    if (stopped_)
      return;

    if (scelta == 1){
    command1 = {0x58, 0x01, 0x11, 0x00, 0x00, 0x00, 0x10, 0x7A};
    }

    // Start an asynchronous operation to send a heartbeat message.
    boost::asio::async_write(socket_, boost::asio::buffer(command1, 8), boost::bind(&client::handle_write, this, _1));
  }

  void handle_write(const boost::system::error_code& ec)
  {
    if (stopped_)
      return;

    if (!ec)
    {
        printf("Pacchetto inviato\n");
	stop();
    }
    else
    {
      std::cout << "Error on heartbeat: " << ec.message() << "\n";
      stop();
    }
  }

  void check_deadline()
  {
    if (stopped_)
      return;

  
    if (deadline_.expiry() <= steady_timer::clock_type::now())
    {     
      socket_.close();
      deadline_.expires_at(steady_timer::time_point::max());
    }

    // Put the actor back to sleep.
    deadline_.async_wait(boost::bind(&client::check_deadline, this));
  }

private:
  bool stopped_;
  tcp::resolver::results_type endpoints_;
  tcp::socket socket_;
  std::string input_buffer_;
  steady_timer deadline_;
  steady_timer heartbeat_timer_;
};

int start_connection(){

try
  {
    boost::asio::io_context io_context;
    tcp::resolver r(io_context);
    client c(io_context);
    c.start(r.resolve("192.168.1.4", "3000"));
    io_context.run();

  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

}

int main(int argc, char* argv[])
{
  
  start_connection();
  return 0;
}

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Hi Rocco,

There are several ways to do this.  Perhaps the easiest is to create a class variable command1, set it, and let the other class functions use it.

If you want to pass it as a parameter, edit the main() function to process the command line parameters and perform the sanity checks.  (If the check is anything more than "is there a command line parameter to be passed?" it's good practice to write another function to handle the parameter checking, just pass argc and argv to it.  Modifiy the start_connection() function declaration to accept a parameter and pass the parameter in the call from main().  It looks (to me) like the value "3000" that's being passed to c.start() is the item you want to derive from a parameter.  If so, the program starting at line 163 could look like this:

int start_connection(char *Parameter){

try
  {
    boost::asio::io_context io_context;
    tcp::resolver r(io_context);
    client c(io_context);
    c.start(r.resolve("192.168.1.4", Parameter));
    io_context.run();

  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

}

int main(int argc, char* argv[])
{
  if (argc == 2) {
    start_connection(argv[1]);
    return 0;
  }
  return 1;
}

Open in new window


client is instantiated start_connection() and "c" is a local variable.  That's not much good for any application that will do more than connect/send/close.  It should probably be a global variable, or created as a pointer and passed to other functions.


Good Luck,
Kent

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial