我正在创建一个客户端应用程序,它使用 ssl Websocket 连接和 ssl Http (Keep-Alive) 连接连接到服务器,并且我正在使用boost::beast
包来做同样的事情。为了检测死连接,我实现了一个简单的乒乓机制。这些都可以正常工作,但是在处理乒乓故障时会出现问题。问题如下:
为了测试我的代码,我连接到远程服务器,发送了几条消息,然后关闭了我的 wifi。正如预期的那样,在一段时间后它检测到它没有收到来自服务器的任何消息,并尝试async_shutdown
为 http 连接和async_close
websocket 连接做一个。我注意到的第一件事是,这两个调用都阻塞了它们各自的线程,直到 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
所以我有两个问题:
- 如果互联网关闭并且无法正确关闭 tcp,我们如何关闭连接。
- 在重新连接之前需要重置的变量
boost::beast
(或建立在 asio 之上的boost::asio
)boost::beast
一直试图调试这个几个小时。任何帮助表示赞赏
编辑
所以我知道我错在哪里了。Alan Birtles 和 Vinnie Falco 都是对的。在您的 ping 计时器到期(并且没有任何处理程序尚未返回)后关闭死 ssl 连接的方法是
- 在您的计时器处理程序中
_stream->lowest_layer().close();
对于 websocket
_ws->lowest_layer().close();
等待您的处理程序之一(通常是读取处理程序)返回错误(通常是 boost::asio::error::operation_aborted 错误)。从那里,排队开始下一次重新连接。(不要在第 1 步之后立即排队重新连接,这会导致我遇到的内存问题。我知道这是 asio 101,但很容易忘记)
对于重置套接字,只需要重置流
_stream.reset(new HttpStream(_ioContext, _sslContext));
对于 websocket
_ws.reset(new WebSocket(_ioContext, _sslContext));