C ++ Каков наилучший способ отключения сокета Boost ASIO SSL? - PullRequest
0 голосов
/ 26 мая 2018

У меня есть клиентское приложение, использующее SSL-сокеты Boost ASIO.Я сталкиваюсь с ошибками соединения, которые оставляют сокет в непригодном для использования состоянии, пока я не перезапущу приложение.Для начала я делаю запрос на соединение с этим кодом:

void apiClient::connect(boost::asio::ip::tcp::resolver::iterator endpoint_list)
{
    boost::asio::ip::tcp::resolver::iterator endpoint_iter = endpoint_list;
    boost::asio::ip::tcp::endpoint endpoint = *endpoint_iter;

    if (!ssl_socket_->lowest_layer().is_open()) {
        ssl_socket_->lowest_layer().async_connect(endpoint,
            boost::bind(&apiClient::handle_connect, this,
            boost::asio::placeholders::error, ++endpoint_iter));
    }
}

Периодически я сталкиваюсь с ошибкой, возвращаемой обработчику соединения, ошибка в ec.message: [Попытка соединения не удалась, потому что подключенная сторона неправильно ответить через определенный промежуток времени или не удалось установить соединение, так как подключенный хост не смог ответить] Код ошибки [10060]

Вот мой обработчик соединения:

void apiClient::handle_connect(const boost::system::error_code& ec, 
    boost::asio::ip::tcp::resolver::iterator endpoint_list)
{
    bool found_error(false);

    if (!ec) {
        ssl_socket_->async_handshake(boost::asio::ssl::stream_base::client,
            boost::bind(&apiClient::send_request, this, 
            boost::asio::placeholders::error));
    }
    else if (endpoint_list != boost::asio::ip::tcp::resolver::iterator()) {
        std::wstring sMsg = boost::str(boost::wformat(L"API server connection failure to host [%s]. Trying next endpoint") % s2ws(endpoint_list->host_name()));
        LogMsg(sMsg);
        found_error = true;
        epList = endpoint_list;
    }
    else {
        std::wstring sMsg = boost::str(boost::wformat(L"API server connection failure.  Error msg [%s] Error code [%d]") % s2ws(ec.message()) % ec.value());
        LogMsg(sMsg);
        found_error = true;
        epList = start_endpoint_list;
    }

    if (found_error) {
        requeue_request(SHUTDOWN_CONN);
    }
}

В моей функции Requeue_requestЯ проверяю количество ошибок, с которыми я столкнулся при запросе, и если оно превышает пороговое значение, я отклоняю запрос и продолжаю.Если я не превысил пороговое значение, я отключаю сокетное соединение перед попыткой переподключения и снова отправляю сообщение.Насколько я понимаю, метод emplace воссоздает экземпляр сокета.

void apiClient::reconnect(SHUTDOWN_CONN_ACTION action)
{
    if (action == SHUTDOWN_CONN) {
        shutdownSocket();
    }

    ssl_socket_.emplace(*io_context_, *ctx_);

    connect_timer.expires_from_now(boost::posix_time::milliseconds(3000));
    connect_timer.async_wait(boost::bind(&apiClient::handleConnectTimer, this, boost::asio::placeholders::error));
}

void CNXGHotKeyAPIClient::shutdownSocket()
{
    boost::system::error_code ec;

    ssl_socket_->next_layer().cancel(ec);
    ssl_socket_->shutdown(ec);
    ssl_socket_->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
    ssl_socket_->lowest_layer().close(ec);
}

Этот дизайн не работает для меня.Когда я сталкиваюсь с какой-либо ошибкой соединения, мое приложение повторяет соединение 3 раза, оно терпит неудачу с той же самой ошибкой все три раза, и сокет остается в состоянии, в котором я не могу использовать его, пока я не перезапущу свое приложение.Сервер, к которому я подключаюсь, выполняет сотни запросов на подключение от приложений python, которые не используют Boost, поэтому я не думаю, что сервер виноват.

Я пытался найти примеры, использующие async_shutdown, но яне могу найти ничего, что помогает мне.Пример по этой ссылке Как правильно отключить сокет asio SSL?

использует следующий код, который я не могу заставить работать.пример кода:

boost::system::error_code ec;
ssl_socket.cancel(ec);
ssl_socket.async_shutdown([](...) { ssl_socket.close(); };

ssl_socket.cancel () даже не существует в моей версии Boost (v1.66), самое близкое, что я могу найти, это ssl_socket.next_layer (). cancel (ec)

Мой вопрос;как отключить сокет после того, как он обнаружил ошибку, чтобы он не оставался в непригодном для использования состоянии?Когда мое приложение сталкивается с ошибками подключения, много раз я не могу восстановить соединение, пока я не перезапущу приложение.Приложение все еще работает и обслуживает действия пользователя, поэтому я знаю, что оно не аварийно завершилось, но сокет находится в состоянии, которое невозможно использовать.Спасибо за любую помощь

1 Ответ

0 голосов
/ 26 мая 2018
  1. Вы не можете отключить сокет SSL.Вы должны закрыть его.
  2. Невозможно повторно подключить сокет после того, как он был подключен, даже если попытка подключения не удалась.Вы должны закрыть его и создать новый.
...