断开连接后,重新连接Boost Beast(Asio)WebSocket和http连接时出错

时间:2018-08-06 10:41:59

标签: c++ boost tcp boost-asio boost-beast

我正在创建一个客户端应用程序,该客户端应用程序使用ssl Websocket连接和ssl Http(保持活动)连接连接到服务器,并且我使用boost::beast包来执行相同的操作。为了检测到断开连接,我已经实现了一种简单的乒乓机制。这些都可以正常工作,但是在处理乒乓球失败时出现问题。问题如下:

为了测试我的代码,我连接到远程服务器,发送了一些消息,然后关闭了wifi。如预期的那样,经过一段时间后,它检测到未收到来自服务器的任何消息,并尝试对HTTP连接执行async_shutdown,对Websocket连接执行async_close。我注意到的第一件事是,这两个呼叫都阻塞了各自的线程,直到wifi备份为止。

在wifi启动后,应用程序尝试在重新连接之前重置流:

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

并为websocket重置ws变量:

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。主持人:xxxxxxxxx。端口: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。主持人:xxxxxxxxx。端口:443。错误:错误的文件描述符

     

161 APIManager.cpp:175(2018-08-06 15:34:39.460674)[0x00007ffff481b700]:从连接接收到错误回调。几秒钟内重新启动连接。连接名称:HttpKeepAliveConn

所以我有2个问题:

  1. 如果Internet断开并且无法正确关闭tcp,我们如何关闭连接。
  2. 在重新连接boost::beast中的变量之前(或为此boost::asio,因为boost::beast是基于asio构建的),需要重置

在尝试调试几个小时后一直处于停滞状态。感谢您的帮助

编辑

所以我弄清楚哪里出了问题。艾伦·比特尔斯(Alan Birtles)和文妮·法尔科(Vinnie Falco)都是对的。在您的ping计时器到期(并且尚未返回任何处理程序)之后,关闭无效的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 个答案:

答案 0 :(得分:0)

我认为asio::ssl::stream在关闭后不能再次使用。

  

如果Internet断开并且无法正确关闭tcp,我们如何关闭连接。

仅允许销毁套接字或流对象。