【问题标题】:Boost Asio SSL not able to receive data for 2nd time onwards (1st time OK)Boost Asio SSL 第二次以后无法接收数据(第一次正常)
【发布时间】:2018-11-14 13:31:59
【问题描述】:

我正在为简单的 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()”。但这一次我无法接收任何数据。但是连接成功了。

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

非常感谢!

【问题讨论】:

  • 我在尝试关闭 SSL 套接字时也注意到一个错误。 ec 返回“流被截断”。我将“SSL_Socket.shutdown()”更改为“SSL_Socket.async_shutdown()”。错误仍然发生。有谁知道如何摆脱这个错误?谢谢。
  • Beast SSL 示例服务器(例如 http-server-sync-sslhttp-server-async-ssl)是否有此问题?请尝试构建和测试这些示例。

标签: c++ ssl boost openssl boost-asio


【解决方案1】:

如果你想复用流实例,你需要使用 openssl lib 函数来操作SSL_Socket.native_handle()。 ssl 关闭后,在开始新的 ssl 握手之前使用SSL_clear()

详情请阅读(注意警告)link

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 关闭问题,link 解释了 boost asio ssl 关闭的工作原理。

在 Boost.Asio 中,shutdown() 操作在发生错误或当事方已发送并接收到 close_notify 消息时被视为完成。

如果您查看 boost.asio (1.68) 源代码 boost\asio\ssl\detail\impl\engine.ipp,它显示了 boost.asio 如何执行 ssl 关闭和 stream_truncated 在有数据时发生未收到对等方的预期读取或 ssl 关闭

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 关闭例程可能会调用 openssl SSL_shutdown() 两次,如果第一次返回 0,openssl 文档允许,但建议调用 SSL_read() 如果第一次返回 0,则调用 SSL_read() 进行双向关闭。

阅读link了解详情。

【讨论】:

    【解决方案2】:

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

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

    这是我给别人的问题。

    【讨论】:

    • 如何设置选项的示例:c++ net::ssl::context ctx (net::ssl::context::tls_server); ctx.set_options (SSL_SESS_CACHE_OFF | SSL_OP_NO_TICKET);
    【解决方案3】:

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

    感谢“Can't implement boost::asio::ssl::stream<boost::asio::ip::tcp::socket> reconnect to server”。他的声明“最纯粹的解决方案是不重用流/套接字对象”摇滚!节省我的时间。

    谢谢。

    【讨论】:

      猜你喜欢
      • 2021-09-09
      • 1970-01-01
      • 2019-07-04
      • 1970-01-01
      • 2023-03-11
      • 2013-08-06
      • 1970-01-01
      • 1970-01-01
      • 2011-08-29
      相关资源
      最近更新 更多