Я пытаюсь написать очень элегантный способ обработки цикла повторного подключения с помощью boost async_connect (...). Проблема в том, что я не вижу способа элегантно решить следующую проблему:
У меня есть TCP-клиент, который должен попытаться асинхронно подключиться к серверу, если соединение не удается из-за того, что сервер отключен или возникает какая-либо другая ошибка, подождите некоторое время и попытайтесь восстановить соединение. Здесь нужно учитывать несколько вещей:
- Избегание глобальных переменных, если это возможно
- Это должно быть асинхронное соединение
Создается очень простой клиент:
tcpclient::tcpclient(std::string host, int port) : _endpoint(boost::asio::ip::address::from_string(host), port), _socket(_ios) {
logger::log_info("Initiating client ...");
}
Попытка подключения к серверу:
void tcpclient::start() {
bool is_connected = false;
while (!is_connected) {
_socket.async_connect(_endpoint, connect_handler);
_ios.run();
}
// read write data (?)
}
Обработчик:
void tcpclient::connect_handler(const boost::system::error_code &error) {
if(error){
// trigger disconnect (?)
logger::log_error(error.message());
return;
}
// Connection is established at this point
// Update timer state and start authentication on server ?
logger::log_info("Connected?");
}
Как правильно начать переподключение каждый раз, когда соединение не удается (или обрывается)? Поскольку обработчик является статическим, я не могу изменить атрибут класса, который указывает на состояние соединения? Я хочу избежать использования хакерских обходных путей для глобальных переменных.
Как правильно решить эту проблему?
Моя попытка будет выглядеть примерно так:
tcpclient.h
enum ConnectionStatus{
NOT_CONNECTED,
CONNECTED
};
class tcpclient {
public:
tcpclient(std::string host, int port);
void start();
private:
ConnectionStatus _status = NOT_CONNECTED;
void connect_handler(const boost::system::error_code& error);
boost::asio::io_service _ios;
boost::asio::ip::tcp::endpoint _endpoint;
boost::asio::ip::tcp::socket _socket;
};
tcpclient.cpp
#include "tcpclient.h"
#include <boost/chrono.hpp>
#include "../utils/logger.h"
tcpclient::tcpclient(std::string host, int port) : _endpoint(boost::asio::ip::address::from_string(host), port),
_socket(_ios) {
logger::log_info("Initiating client ...");
logger::log_info("Server endpoint: " + _endpoint.address().to_string());
}
void tcpclient::connect_handler(const boost::system::error_code &error) {
if(!error){
_status = CONNECTED;
logger::log_info("Connected.");
}
else{
_status = NOT_CONNECTED;
logger::log_info("Failed to connect");
_socket.close();
}
}
void tcpclient::start() {
while (_status == NOT_CONNECTED) {
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
_socket.close();
_socket.async_connect(_endpoint, std::bind(&tcpclient::connect_handler, this, std::placeholders::_1));
_ios.run();
}
}
Проблема в том, что переподключение не работает должным образом, и приложение по какой-то причине зависает? Кроме того, переподключение также кажется проблематичным, как только соединение было установлено и затем сброшено (например, из-за сбоя / закрытия сервера).