提升 Asio SSL 无法第二次接收数据(第一次确定)

Boost Asio SSL not able to receive data for 2nd time onwards (1st time OK)

本文关键字:数据 第一次 SSL Asio 第二次 提升      更新时间:2023-10-16

我正在为简单的RESTful服务器开发Boost Asio和Boost Beast。对于普通的HTTP和TCP套接字,它可以完美地工作。我用JMeter对其进行了负载测试,一切正常。

我尝试添加 SSL 套接字。我设置了"ssl::context",也称为"async_handshake((" - 与普通套接字相比,SSL 的额外步骤。它只是第一次工作。客户端可以与我(服务器(连接,我也可以通过"boost::beast::http::async_read(("接收数据。

因为这是RESTful,所以连接将在请求和响应后断开。我调用"SSL_Socket.shutdown((",然后调用"SSL_Socket.lowest_layer((.close(("来关闭SSL套接字。

当下一个传入请求时,客户端能够与我(服务器(连接。我调用了"SSL_Socket.async_handshake((",然后跟着"boost::beast::http::async_read(("。但是这次我无法接收任何数据。但连接已成功建立。

有人知道我错过了什么吗?

谢谢!

如果要重用流实例,则需要使用 openssl lib 函数操作SSL_Socket.native_handle()。SSL 关机后,在开始新的 SSL 握手之前使用SSL_clear()

详情请阅读(注意警告(链接

SSL_clear(( 重置 SSL 对象以允许另一个连接。但是,重置操作会保留上次会话的多个设置(其中一些设置是在上次握手期间自动进行的( .........

警告

SSL_clear(( 重置 SSL 对象以允许另一个连接。但是,重置操作会保留上次会话的多个设置(其中一些设置是在上次握手期间自动进行的(。它仅对共享这些设置的完全相同的对等方的新连接有意义,如果该对等方在连接之间更改其设置,则可能会失败。使用序列SSL_get_session(3(;SSL_new(3(;SSL_set_session(3(;SSL_free(3(而是为了避免此类故障(或简称SSL_free(3(;SSL_new(3( 如果不需要会话重用(。

关于 SSL 关闭问题,链接解释提升 asio SSL 关闭的工作原理。

在 Boost.Asio 中,如果出现错误或一方发送和接收了close_notify消息,则认为 shutdown(( 操作已完成。

如果您查看boost.asio(1.68(源代码boost\asio\ssl\detail\impl\engine.ipp,它显示了boost.asio如何执行SSL关闭,并且当有数据要读取或SSL关闭预期未收到时,会发生stream_truncated

int engine::do_shutdown(void*, std::size_t)
{
int result = ::SSL_shutdown(ssl_);
if (result == 0)
result = ::SSL_shutdown(ssl_);
return result; 
} 
const boost::system::error_code& engine::map_error_code(
boost::system::error_code& ec) const
......
// If there's data yet to be read, it's an error.
if (BIO_wpending(ext_bio_))
{
ec = boost::asio::ssl::error::stream_truncated;
return ec;
}
......
// Otherwise, the peer should have negotiated a proper shutdown.
if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)
{
ec = boost::asio::ssl::error::stream_truncated;
}
}

您还可以看到 boost.asio ssl 关闭例程可能会调用 opensslSSL_shutdown()两次,如果第一个返回 0,openssl 文档允许它,但如果第一个返回 0,建议调用SSL_read()进行双向关闭SSL_shutdown()

有关详细信息,请阅读链接。

我遇到了类似的问题,第二次我的异步接受总是失败,会话 ID 未初始化。

我解决了在上下文或调用SSL_CTX_set_session_id_context的问题 使用上下文选项SSL_SESS_CACHE_OFF和SSL_OP_NO_TICKET设置上下文缓存模式。

这是我对别人问题的美分。

我设法通过将"ssl::stream"套接字切换到"boost::optional",然后在每次套接字关闭和关闭时添加"SSL_Socket.emplace(io_context,oSSLContext("来解决问题。

在"无法实现 boost::asio::ssl::stream<boost::asio::ip::tcp::socket>重新连接到服务器"时,大功劳。他的声明">最纯粹的解决方案是不重复使用流/套接字对象"摇滚!节省我的时间。

谢谢。