Ошибка повторного подключения веб-сокета boost beast (asio) и соединения http после отключения

Я создаю клиентское приложение, которое подключается к серверу с помощью соединения ssl Websocket и ssl Http (Keep-Alive), и я использую boost::beast пакет, чтобы сделать то же самое. Чтобы обнаружить мертвое соединение, я реализовал простой механизм пинг-понга. Все они работают нормально, но возникает проблема при обработке ошибки пинг-понга. Вопрос заключается в следующем:

Для тестирования моего кода я подключился к удаленному серверу, отправил несколько сообщений, а затем отключил Wi-Fi. Как и ожидалось после определенного периода времени, он обнаружил, что не получил никакого сообщения от сервера, и попытался выполнить async_shutdown для http-соединения и async_close для подключения через веб-сокет. Первое, что я заметил, было то, что оба этих звонка блокируют их соответствующие нити, пока Wi-Fi не восстановлен.

И после того, как Wi-Fi включен, приложение пытается сбросить поток перед повторным подключением:

void HttpKeepAliveConnection::recreateSocket()
{
    _receivedPongForLastPing = true;
    _sslContext.reset(new boost::asio::ssl::context({boost::asio::ssl::context::sslv23_client}));
    _stream.reset(new HttpStream(_ioContext, *_sslContext));
}

И сбросьте переменную ws для websocket:

void WebsocketConnection::recreateSocket()
{
    _receivedPongForLastPing = true;
    _sslContext.reset(new boost::asio::ssl::context({boost::asio::ssl::context::sslv23_client}));
    _ws.reset(new WebSocket(_ioContext, *_sslContext));
}

К сожалению, это не удается либо в on_connect, либо в on_ssl_handshake. Ниже приведены мои журналы:

156 AsioConnectionBase.cpp: 53 (2018-08-06 15: 34: 38.458536) [0x00007ffff601e700]: запущена последовательность подключения. Имя соединения: HttpKeepAliveConn

157 AsioConnectionBase.cpp: 122 (2018-08-06 15: 34: 38.459802) [0x00007ffff481b700]: не удалось установить соединение с пунктом назначения. Соединение не удалось. Имя соединения: HttpKeepAliveConn. Хост: хххххххх. Порт: 443. Ошибка: операция отменена

158 APIManager.cpp:175 (2018-08-06 15:34:38.459886) [0x00007ffff481b700]: получен обратный вызов ошибки из соединения. Перезапуск соединения через сек. Имя соединения: HttpKeepAliveConn

159 AsioConnectionBase.cpp: 53 (2018-08-06 15: 34: 39.460009) [0x00007ffff481b700]: запущена последовательность подключения. Имя соединения: HttpKeepAliveConn

160 HttpKeepAliveConnection.cpp: 32 (2018-08-06 15: 34: 39.460515) [0x00007ffff481b700]: сбой рукопожатия ssl. Соединение не удалось. Имя соединения: HttpKeepAliveConn. Хост: хххххххх. Порт: 443. Ошибка: неверный дескриптор файла

161 APIManager.cpp:175 (2018-08-06 15:34:39.460674) [0x00007ffff481b700]: получен обратный вызов ошибки из соединения. Перезапуск соединения через сек. Имя соединения: HttpKeepAliveConn

Итак, у меня есть 2 вопроса:

  1. Как мы можем закрыть соединение, если интернет не работает и правильное закрытие протокола TCP невозможно?
  2. Перед повторным подключением, какие переменные в boost::beast (или в этом отношении boost::asio как boost::beast построен на вершине ASIO), который должен быть сброшен

Застрял, пытаясь отладить это на пару часов. Любая помощь приветствуется

РЕДАКТИРОВАТЬ

Поэтому я понял, где я ошибся. И Алан Биртлз, и Винни Фалько были правы. Способ закрыть мертвое соединение ssl после того, как истек таймер пинга (и ни один из обработчиков еще не вернулся),

  1. В вашем таймере обработчик
_stream->lowest_layer().close();

Для веб-сокета

_ws->lowest_layer().close();
  1. Подождите, пока один из ваших обработчиков (обычно обработчик чтения) вернется с ошибкой (обычно ошибка boost:: asio:: error:: operation_aborted). Оттуда, очередь на начало следующего переподключения. (Не ставьте в очередь переподключение сразу после шага 1, это приведет к проблемам с памятью, с которыми я столкнулся. Я знаю, что это asio 101, но легко забыть)

  2. Для сброса сокета все, что требуется, это сбросить поток

_stream.reset(new HttpStream(_ioContext, _sslContext));

Для веб-сокета

_ws.reset(new WebSocket(_ioContext, _sslContext));

1 ответ

Я не думаю asio::ssl::stream может быть использован снова после закрытия.

Как мы можем закрыть соединение, если интернет не работает и правильное закрытие протокола TCP невозможно?

Просто позвольте сокету или объекту потока быть уничтоженным.

Другие вопросы по тегам