简体   繁体   中英

How to pass array parameter to a function for a TCP client in C++ and Boost

I'm using a non-blocking TCP client in C++ and Boost under Ubuntu to send data to a TCP server in this format std::array<uint8_t, 8> command1;

It works very well, but I need to change the command1 content depending on users actions so I would like to find a solution to directly call the start_connection() function and pass the command1 parameter in order to send it with start_write() function.

What is the best way to do this? Is there any faster and professional way to pass the command1 to start_write() function?

    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);
        }
      }

EDIT1: for some reason, the code I previously posted wasn't complete. This is the missing part:

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;
}

There are many ways to do it.

Here is possible implementation:

  void start_write(int scelta, std::array<uint8_t,8> inVec)
  {
    if (stopped_)
      return;

    std::shared_ptr<std::array<uint8_t,8>> copy = 
            std::make_shared<std::array<uint8_t,8>>(inVec);

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

as you can see start_write takes array as parameter. Because you are using async functions, you need to ensure that lifetime of passed array into buffer function is prolonged until async operation finished. You can use shared_ptr to do it. To extend lifetime of inVec copy owned by shared_ptr you can bind it to handle_write function:

  void handle_write(const boost::system::error_code& ec, std::shared_ptr<std::array<uint8_t,8>>)
  {
    if (stopped_)
      return;

in above function shared_ptr is not referenced, it was only used for binding to capture this object and increments its reference counter.

Instead of using bind , you can use lambda, then shared_ptr can be captured by value into lambda.

Here compiled code

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