boost asio - 来自一个线程的 SSL async_read 和 async_write

Posted

技术标签:

【中文标题】boost asio - 来自一个线程的 SSL async_read 和 async_write【英文标题】:boost asio - SSL async_read and async_write from one thread 【发布时间】:2013-08-23 18:28:45 【问题描述】:

我知道基于 OpenSSL,boost asio SSL 实现,不允许并发 SSL_read() 和 SSL_write()(即 SSL_read() 和 SSL_write() 由不同的线程执行)。

从同一个线程在 SSL 套接字上调用 boost asio async_read() 和 async_write() 是否安全?

谢谢

【问题讨论】:

【参考方案1】:

boost::asio::ssl:::stream 的要求是为了线程安全;它没有要求哪个线程可以发起操作:

不同的对象:安全。

共享对象:不安全。应用程序还必须确保所有异步操作都在同一个隐式或显式链中执行。

如果应用程序只有一个线程处理io_service,并且async_read()async_write() 是从该线程内启动的,那么它是安全的,因为操作和完成处理程序是在隐式的链。

另一方面,如果多个线程正在处理io_service,则需要显式的strandasync_read()async_write() 操作需要从 strand 中启动,并且完成处理程序需要由相同的 strand 包装。

有关 Boost.Asio 的线程安全要求、strands 和组合操作的更多详细信息,请考虑阅读this 答案。

【讨论】:

【参考方案2】:

调用async_read()async_write() 从同一个线程在 SSL 套接字上是安全的,但在一般情况下不足以避免并发问题ssl::流。实际需求在ssl::stream documentation中提供:

线程安全 (...) 共享对象:不安全。应用程序还必须确保所有异步操作都在同一个隐式或显式链中执行。

当然,标准的 boost::asio 要求确保:

async_read 处理程序获取之前不会执行其他读取操作 调用,并且 在调用 async_write 处理程序之前不会执行其他写入操作。

也必须满足。

请注意,允许在写操作正在进行时安排读操作,反之亦然。由于通过BIO 机制异步处理OpenSSL 的网络需求,ssl::stream 可以同时进行异步读写操作。 SSL_read()SSL_write() 通过返回 SSL_ERROR_WANT_READSSL_ERROR_WANT_WRITE 错误代码来表明他们的通信需求。 ssl::stream 实现使用这些错误代码来异步调度网络操作。对ssl::stream 的读取或写入操作可能需要对底层网络套接字进行多次读取和写入操作以及对SSL_read() / SSL_write() 的多次调用,这将由异步网络操作完成处理程序执行(特别是不是来自原始async_read/async_write 调用),这就是为什么保证async_readasync_write 不被同时调用是不够的,还需要一个链。

【讨论】:

【参考方案3】:

这是安全的。但是在同一个套接字上模拟 2 个或更多 async_write-s 是不安全的,并且会经常出现段错误(至少对于 SSL 情况)。

【讨论】:

它不会出现段错误,它会交错数据。

以上是关于boost asio - 来自一个线程的 SSL async_read 和 async_write的主要内容,如果未能解决你的问题,请参考以下文章

boost::asio::async_write 写入 ssl::stream 成功但服务器未获取

在 Boost.Asio 中同时使用 SSL 套接字和非 SSL 套接字?

boost::asio::ssl::context 可以在多个 SSL 流之间共享吗?

如何接受boost :: asio :: ssl :: stream 作为boost :: asio :: ip :: tcp :: socket类型的参数

boost/asio/ssl 抛出“未定义的引用”错误

boost asio ssl async_shutdown 总是以错误结束?