如何优雅地关闭 boost asio ssl 客户端?
Posted
技术标签:
【中文标题】如何优雅地关闭 boost asio ssl 客户端?【英文标题】:How to gracefully shutdown a boost asio ssl client? 【发布时间】:2014-04-29 19:08:34 【问题描述】:客户端进行了一些ssl::stream<tcp_socket>::async_read_some()
/ssl::stream<tcp_socket>::async_write()
调用,在某些时候需要退出,即需要关闭连接。
调用ssl::stream<tcp_socket>::lowest_layer().close()
有效,但(正如预期的那样)服务器(openssl s_server -state ...
命令)在关闭连接时报告错误。
看API的正确方法似乎是调用ssl::stream<tcp_socket>::async_shutdown()
。
现在基本上有两种情况需要关机:
1) 客户端在async_read_some()
回调中,并对来自服务器的“退出”命令作出反应。从那里调用 async_shutdown()
在关闭回调中产生“短读”错误。
这令人惊讶,但在谷歌搜索后这似乎是正常行为 - 似乎必须检查它是否是一个真正的错误:
// const boost::system::error_code &ec
if (ec.category() == asio::error::get_ssl_category() &&
ec.value() == ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ))
// -> not a real error, just a normal TLS shutdown
不过,TLS 服务器似乎很高兴 - 它报告:
DONE
shutting down SSL
CONNECTION CLOSED
2) async_read_some()
处于活动状态 - 但用户决定退出客户端(例如,通过标准输入的命令)。当从该上下文调用async_shutdown()
时,会发生以下情况:
async_read_some()
回调执行时带有“短读”错误代码 - 现在是预期的
async_shutdown()
回调执行时带有 decryption failed or bad record mac 错误代码 - 这是意料之外的
服务端不报错。
因此我的问题是如何使用 boost asio 正确关闭 TLS 客户端。
【问题讨论】:
【参考方案1】:从第二个上下文中解决“解密失败或坏记录 mac”错误代码的一种方法是:
a) 从标准输入处理程序调用内部:
ssl::stream<tcp_socket>::lowest_layer()::shutdown(tcp::socket::shutdown_receive)
b) 这会导致 async_read_some()
回调以“短读”“错误”代码执行
c) 在那个“错误”条件下的回调中 async_shutdown()
被调用:
// const boost::system::error_code &ec
if (ec.category() == asio::error::get_ssl_category() &&
ec.value() == ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ))
// -> not a real error:
do_ssl_async_shutdown();
d) async_shutdown()
回调执行时带有“短读”错误代码,我们最终从这里调用:
这些步骤会导致连接关闭,而客户端或服务器端没有任何奇怪的错误消息。
例如,当使用 openssl s_server -state ...
作为服务器时,它会报告 sutdown:
(最后一行是因为命令接受新连接)
另类
除了lowest_layer()::shutdown(tcp::socket::shutdown_receive)
,我们也可以调用
ssl::stream<tcp_socket>::lowest_layer()::cancel()
启动正确的关机。它具有相同的效果,即它产生计划的async_read_some()
回调的执行(但带有operation_aborted
错误代码)。因此,可以从那里拨打async_shutdown()
:
if (ec.value() == asio::error::operation_aborted)
cout << "(not really an error)\n";
do_async_ssl_shutdown();
【讨论】:
以上是关于如何优雅地关闭 boost asio ssl 客户端?的主要内容,如果未能解决你的问题,请参考以下文章
boost asio ssl async_shutdown 总是以错误结束?
boost::asio::async_write 写入 ssl::stream 成功但服务器未获取
如何接受boost :: asio :: ssl :: stream 作为boost :: asio :: ip :: tcp :: socket类型的参数