boost::beast ssl tcp stream:优雅地断开并重新连接

3

我有一个boost::beast的SSL流数据成员:

class HttpsClient
{
    ...
    asio::ssl::context _ssl_ctx;
    beast::ssl_stream<beast::tcp_stream> _stream;
};

在构建时,我使用以下方式使用asio::io_context和ssl上下文初始化流:

namespace ssl = boost::asio::ssl;

ssl::context sslContext()
{
    ssl::context ssl_ctx {ssl::context::tlsv12_client};
    ssl_ctx.set_verify_mode(ssl::context::verify_peer | ssl::context::verify_fail_if_no_peer_cert);
    ssl_ctx.set_default_verify_paths();
    boost::certify::enable_native_https_server_verification(ssl_ctx);
    return ssl_ctx;
}

HttpsClient::HttpsClient(asio::io_context& ctx)
    : _ssl_ctx(sslContext())
    , _stream(ctx, _ssl_ctx)
{}

我的connect函数会同步解析端点,连接到它,并执行SSL握手。

void HttpsClient::connect(const std::string& host, std::uint16_t port, const std::string& path)
{
    tcp::resolver resolver {_stream.get_executor()};
    tcp::resolver::results_type end_point = resolver.resolve(host, std::to_string(port));

    beast::get_lowest_layer(_stream).connect(end_point);
    beast::get_lowest_layer(_stream).socket().set_option(tcp::no_delay {true});

    SSL_set_tlsext_host_name(_stream.native_handle(), host.c_str());
    _stream.handshake(ssl::stream_base::client);
}

连接成功后,我会开始进行async_read操作,而当我想要发送请求时,则使用同步版本:

void HttpsClient::write(beast::http::request<beast::http::string_body>& request)
{
    request.prepare_payload();
    http::write(_stream, request);
}

这一切都按预期工作。

我遇到的问题是,我想断开然后重新连接流。

我尝试了几种不同的方法来关闭连接:

取消未完成的异步读取并关闭流:

_stream.next_layer().cancel();
_stream.shutdown();

一旦 shutdown 完成,我似乎能够重新连接,但尝试写入流会失败,并显示 "protocol is shutdown"

在收到 "protocol is shutdown" 后,任何重新连接的尝试都会受到 "Operation canceled" 的影响。

取消未完成的 async_read 并关闭底层 TCP 流:

_stream.next_layer().cancel();
_stream.next_layer().close();

一旦close完成,似乎仍然可以重新连接,但现在尝试写入流会失败并显示"wrong version number"
收到"wrong version number"后,任何重新连接的尝试都会收到"unspecified system error"
问题:
- 是否可以断开流,然后重新连接和重用它? - 如果可以,我需要执行哪些程序来允许此操作?

这个与websocket相关的问题(https://github.com/boostorg/beast/issues/1778),但可能ssl流具有类似的要求,建议重新创建整个流...暗示重用已断开的流是不可能的。 - Steve Lorimer
1
我认为你可以将评论有用地推广为自我回答。 - sehe
1个回答

2

这个问题与WebSocket有关,但可能SSL流具有类似的要求,建议重新创建整个流...表明无法重用已断开的流。

当然,重新创建流确实有效,这表明这确实是情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接