Ошибка повторного подключения веб-сокета 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 вопроса:
- Как мы можем закрыть соединение, если интернет не работает и правильное закрытие протокола TCP невозможно?
- Перед повторным подключением, какие переменные в
boost::beast
(или в этом отношенииboost::asio
какboost::beast
построен на вершине ASIO), который должен быть сброшен
Застрял, пытаясь отладить это на пару часов. Любая помощь приветствуется
РЕДАКТИРОВАТЬ
Поэтому я понял, где я ошибся. И Алан Биртлз, и Винни Фалько были правы. Способ закрыть мертвое соединение ssl после того, как истек таймер пинга (и ни один из обработчиков еще не вернулся),
- В вашем таймере обработчик
_stream->lowest_layer().close();
Для веб-сокета
_ws->lowest_layer().close();
Подождите, пока один из ваших обработчиков (обычно обработчик чтения) вернется с ошибкой (обычно ошибка boost:: asio:: error:: operation_aborted). Оттуда, очередь на начало следующего переподключения. (Не ставьте в очередь переподключение сразу после шага 1, это приведет к проблемам с памятью, с которыми я столкнулся. Я знаю, что это asio 101, но легко забыть)
Для сброса сокета все, что требуется, это сбросить поток
_stream.reset(new HttpStream(_ioContext, _sslContext));
Для веб-сокета
_ws.reset(new WebSocket(_ioContext, _sslContext));
1 ответ
Я не думаю asio::ssl::stream
может быть использован снова после закрытия.
Как мы можем закрыть соединение, если интернет не работает и правильное закрытие протокола TCP невозможно?
Просто позвольте сокету или объекту потока быть уничтоженным.