Синхронный клиент на boost::asio
От: plastictown Норвегия  
Дата: 08.12.17 21:14
Оценка:
Доброго времени суток! Собственно, клиент написан и работает, хотелось бы уточнить отдельные детали. Клиент синхронный, т.к. используется как транспорт для modbus-tcp, а городить синхронность через асинхронные вызовы это как-то странно, но если нужда заставит, придется.
Сделал синхронные read/write с таймаутом + автореконнект при расконнекте и метод для ожидания поступления данных. Хотелось бы получить рекомендации по возможному увеличению быстродействия кода, т.к. один запрос/ответ занимает в средне 33 мс, а если в проекте, скажем, тысяча переменных (скада), то это уже 33 сек, что неприемлемо.

Теперь код.
метод для подключения и переподключения. В 'to' записывается очень примерный интервал затраченного времени.

bool try_connect(const std::string& ip, uint32_t port, int32_t n_times, uint32_t* to = NULL)
  {
    std::stringstream ss;
    ss << port;
    tcp::resolver::query query(ip, ss.str());
    tcp::resolver::iterator iter = tcp::resolver(*m_io).resolve(query);
    for (int32_t i = 0; i < n_times; i++)
    {
      try
      {
        m_sock->close();
        m_sock->connect(*iter);
      }
      catch (std::exception& e)
      {
        boost::this_thread::sleep(boost::posix_time::millisec(5*(i+1)));
        if (to != NULL) *to += 5 * (i + 1);
        continue;
      }
      if (m_sock->is_open()) return true;
    }
    return false;
  }


Метод ожидания данных. Профилировщик из VS говорит, что на этот метод уходит 80% времени.

bool wait_for_data(uint32_t size_in_bytes, uint32_t timeout, bool try_reconnect)
  {
    if (size_in_bytes == 0) return true;

    uint32_t to = 0u;

    if (!m_sock->is_open())
    {
      if (try_reconnect)
      {
        if (!try_connect(m_ip, m_port, 3u, &to))
          return false;
      }
    }

    if (!m_sock->is_open()) return false;

    if (bytes_available(*m_sock) >= size_in_bytes) return true;

    while (to <= timeout)
    {
      if (bytes_available(*m_sock) >= size_in_bytes) return true;
      boost::this_thread::sleep(boost::posix_time::millisec(1));
      to++;
    }
    return false;
  }


Количество данных, готовых для чтения:

size_t bytes_available(boost::asio::ip::tcp::socket& s)
  {
    boost::asio::socket_base::bytes_readable command(true);
    s.io_control(command);
    return command.get();
  }


Встречал часто такую реализацию таймаутов:

void configure_socket_to(boost::asio::ip::tcp::socket& socket, uint32_t ms)
  {
#if defined( WIN32 )
    int32_t timeout = ms;
    setsockopt(socket.native(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
    setsockopt(socket.native(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout));
#else
    struct timeval tv;
    tv.tv_sec  = 0;
    tv.tv_usec = ms;
    setsockopt(socket.native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    setsockopt(socket.native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
#endif
  }


У меня этот код не заработал по крайней мере на виндах.

Ну и собственно чтение данных:

 bool receive ( void* out, const size_t sz)
  {

    if (!m_sock->is_open())
      if (!try_connect())
        return false;

    //--- connected ---//

    if (bytes_available(*m_sock) < sz)
      if (!wait_for_data(sz, m_to, true))
        return false;

    //--- have enough data in port ---//

    try
    {
      m_sock->read_some(boost::asio::buffer(out, sz));
    }
    catch(std::exception& e)
    {
      std::cerr << e.what() << std::endl;
      return false;
    }
      return true;
  }


Буду рад любым замечаниям и предложениям. Спасибо!
boost::asio synchronous_client
Re: Синхронный клиент на boost::asio
От: antropolog  
Дата: 09.12.17 02:27
Оценка:
Здравствуйте, plastictown, Вы писали:

P>Клиент синхронный, т.к. используется как транспорт для modbus-tcp, а городить синхронность через асинхронные вызовы это как-то странно, но если нужда заставит, придется.


Re[2]: Синхронный клиент на boost::asio
От: plastictown Норвегия  
Дата: 09.12.17 09:11
Оценка:
Здравствуйте, antropolog, Вы писали:

P>>Клиент синхронный, т.к. используется как транспорт для modbus-tcp, а городить синхронность через асинхронные вызовы это как-то странно, но если нужда заставит, придется.


A>


* Я художник, я так вижу
* Это вообще-то мой первый опыт работы с сетями, поэтому можно все-таки по делу?
Re[3]: Синхронный клиент на boost::asio
От: Mr.Delphist  
Дата: 11.12.17 14:15
Оценка:
Здравствуйте, plastictown, Вы писали:

P>* Я художник, я так вижу

P>* Это вообще-то мой первый опыт работы с сетями, поэтому можно все-таки по делу?

Сеть — это асинхронная среда. Исходите из этого с самого начала. Оборачивание в синхронные вызовы лучше оставьте как прерогативу самого верхнего слоя (т.е. тем, кто пользуется Вашей либой).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.