如何为Boost.Asio的ssl::stream正确添加缓冲?
问题背景与需求
我们代码库中有直接使用OpenSSL的C++网络代码,为提升可维护性,计划用Boost.Asio替代。该代码用于服务器与客户端间的双向认证TLS连接,支持收发字节数组。基准测试显示Asio版本运行时间是OpenSSL版本的近5倍,原因是OpenSSL版本用了网络通信缓冲,而Asio版本没有。由于应用频繁收发大量小消息,缓冲对性能至关重要(API包含flush函数可按需刷新发送缓冲区)。
手动实现了用std::vector<byte>管理缓冲的逻辑,让应用先写入缓冲,仅调用flush时才发送网络数据,性能有所提升,但仍比OpenSSL版本慢约30%。注意到Boost.Asio的buffered_stream类似乎正是所需,但不清楚底层流为boost::asio::ssl::stream类型时如何正确构造。另外,如果这种方法不可行,有没有更好的Asio缓冲I/O方式能达到和OpenSSL版本相近的性能?
尝试的代码
using namespace boost::asio; using ssl_socket_t = ssl::stream<ip::tcp::socket>; // 此函数(在别处定义)返回配置正确的客户端ssl::context对象 ssl::context tlsClientContext(std::string_view certificate_filename, std::string_view private_key_filename, std::string_view trust_store_filename); // 尝试实现如下API: buffered_stream<ssl_socket_t> connect(std::string_view hostname, std::uint16_t port, std::string_view certificate_filename, std::string_view private_key_filename, std::string_view trust_store_filename) { auto ssl_ctx = tlsClientContext(certificate_filename, private_key_filename, trust_store_filename); auto ssl_socket = ssl_socket_t(system_executor(), ssl_ctx); auto resolver = ip::tcp::resolver(ssl_socket.get_executor()); connect(ssl_socket.lowest_layer(), resolver.resolve(hostname, std::to_string(port))); ssl_socket.handshake(ssl_socket_t::client); return buffered_stream<ssl_socket_t>(std::move(ssl_socket)); } void read(buffered_stream<ssl_socket_t>& stream, std::byte* data, std::size_t num_bytes) { boost::asio::read(stream, buffer(data, num_bytes)); } void write(buffered_stream<ssl_socket_t>& stream, const std::byte* data, std::size_t num_bytes) { boost::asio::write(stream, buffer(data, num_bytes)); } void flush(buffered_stream<ssl_socket_t>& stream) { stream.flush(); }
编译问题
上述connect函数无法编译:buffered_stream构造函数要求第一个参数为左值;若移除std::move,又因ssl::stream不可拷贝而编译失败。原本期望buffered_stream支持传入待缓冲流的右值引用,但不知道如何实现。
解决方案
1. 正确构造buffered_stream的方法
Boost.Asio的buffered_stream在C++11及以后版本支持移动构造,可通过以下方式解决构造问题:
- 使用make_buffered_stream辅助函数:它天然支持接收右值,代码调整如下:
return make_buffered_stream(std::move(ssl_socket)); - 显式移动构造:确保Boost版本在1.70+(该版本后
buffered_stream完善了右值构造支持),直接返回移动构造的对象:return buffered_stream<ssl_socket_t>(std::move(ssl_socket));
2. 优化性能的其他方案
如果buffered_stream仍无法达到预期性能,可尝试以下方案:
- 自定义缓冲区大小:默认缓冲区大小可能不匹配小消息场景,构造时指定合适的大小(比如8KB或16KB,根据实际业务调整):
return make_buffered_stream(std::move(ssl_socket), 8192); - 手动实现灵活缓冲逻辑:自己维护动态缓冲区,完全控制消息合并与发送时机,示例代码如下:
class BufferedSslStream { public: BufferedSslStream(ssl_socket_t socket) : socket_(std::move(socket)) {} void write(const std::byte* data, std::size_t num_bytes) { buffer_.insert(buffer_.end(), data, data + num_bytes); } void flush() { if (!buffer_.empty()) { boost::asio::write(socket_, boost::asio::buffer(buffer_)); buffer_.clear(); } } void read(std::byte* data, std::size_t num_bytes) { boost::asio::read(socket_, boost::asio::buffer(data, num_bytes)); } private: ssl_socket_t socket_; std::vector<std::byte> buffer_; }; - 启用OpenSSL内部缓冲:利用OpenSSL原生API开启缓冲模式,减少系统调用次数:
SSL* ssl_handle = ssl_socket.native_handle(); SSL_set_mode(ssl_handle, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
内容的提问来源于stack exchange,提问作者Dave Edwards
相关产品推荐
相关产品推荐

