Доброго времени суток! Собственно, клиент написан и работает, хотелось бы уточнить отдельные детали. Клиент синхронный, т.к. используется как транспорт для 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;
}
Буду рад любым замечаниям и предложениям. Спасибо!
Здравствуйте, plastictown, Вы писали:
P>Клиент синхронный, т.к. используется как транспорт для modbus-tcp, а городить синхронность через асинхронные вызовы это как-то странно, но если нужда заставит, придется.
Здравствуйте, antropolog, Вы писали:
P>>Клиент синхронный, т.к. используется как транспорт для modbus-tcp, а городить синхронность через асинхронные вызовы это как-то странно, но если нужда заставит, придется.
A>
* Я художник, я так вижу
* Это вообще-то мой первый опыт работы с сетями, поэтому можно все-таки по делу?
Здравствуйте, plastictown, Вы писали:
P>* Я художник, я так вижу
P>* Это вообще-то мой первый опыт работы с сетями, поэтому можно все-таки по делу?
Сеть — это
асинхронная среда. Исходите из этого с самого начала. Оборачивание в синхронные вызовы лучше оставьте как прерогативу самого верхнего слоя (т.е. тем, кто пользуется Вашей либой).