Как передать параметр массива в функцию для TCP-клиента в C ++ и Boost - PullRequest
1 голос
/ 23 октября 2019

Я использую неблокирующий TCP-клиент в C ++ и Boost под Ubuntu для отправки данных на TCP-сервер в этом формате std::array<uint8_t, 8> command1;

Это работает очень хорошо, но мне нужно изменить команду1содержание зависит от действий пользователя, поэтому я хотел бы найти решение для непосредственного вызова функции start_connection() и передачи параметра command1 для отправки его с помощью функции start_write().

Как лучше всего это сделатьэто? Есть ли более быстрый и профессиональный способ передачи команды 1 в функцию start_write()?

    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: по какой-то причине ранее опубликованный код был неполным. Это недостающая часть:

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

1 Ответ

1 голос
/ 23 октября 2019

Есть много способов сделать это.

Здесь возможна реализация:

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

, как вы можете видеть start_write принимает массив в качестве параметра. Поскольку вы используете асинхронные функции, вам необходимо убедиться, что время жизни переданного массива в буферную функцию продлено до завершения асинхронной операции. Вы можете использовать shared_ptr, чтобы сделать это. Чтобы продлить срок действия inVec копии, принадлежащей shared_ptr, вы можете привязать ее к функции handle_write:

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

в вышеприведенной функции shared_ptr не указана, она использовалась только для привязки для захватаэтот объект и увеличивает его счетчик ссылок.

Вместо использования bind вы можете использовать лямбду, тогда shared_ptr может быть захвачено по значению в лямбду.

Здесь скомпилированный код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...