为什么没有asio::ssl::iostream?(以及如何实施)
Why is there no asio::ssl::iostream? (and how to implement it)
我目前正在探索Asio库,并拥有用于常规TCP连接的工作代码。我使用了asio::ip::tcp::iostream
对象,因为我想传输的东西已经可以从iostreams序列化/反序列化了,所以这真的很方便,对我来说效果很好
然后我尝试切换到SSL连接,这时一切都变得疯狂了。显然,没有内置的支持来获得与所有其他协议支持的安全连接相同的iostream接口。从设计的角度来看,这真的让我很困惑。有什么原因造成这种情况吗?
我知道"如何创建boost ssl iostream?"中的讨论?它以使用boost提供iostream功能的包装器类结束。除此之外,根据一条评论,该实现存在缺陷,这也没有提供与其他协议(basic_socket_iostream
)相同的接口,后者也允许例如设置过期时间和关闭连接。(我也在非boost版本中使用asio,如果可能的话,我希望避免添加boost作为额外的依赖项)。
所以,我想我的问题是:
- 要获得SSL连接的basic_socket_ostream,我到底需要实现什么?我认为这将是
asio::basic_streambuf
或asio::basic_socket_streambuf
的派生,但不知何故,我不知道它们是如何工作的,需要进行调整。。只是有一堆奇怪的指针移动和缓冲区分配,对我来说,文档不清楚什么时候会实现什么 - 为什么这一点一开始就不存在?让这一个协议的行为与任何其他协议完全不同似乎是非常不合理的,因此需要进行重大重构来更改基于
tcp::iostream
的项目以支持安全连接
好吧,我遇到的问题是ssl::流实际上两者都不起作用:我没有提供套接字,但它也没有提供与其他协议兼容的流接口,是的,从这个意义上说,它的行为与其他协议非常不同(没有明显的原因)
我认为流的行为与其他协议没有任何不同(请参阅https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/overview/core/streams.html):
流、短读取和短写入
Boost中的许多I/O对象。Asio是以流为导向的。这意味着:
没有消息边界。正在传输的数据是一个连续的字节序列
读取或写入操作传输的字节数可能少于请求的字节数。这被称为短读或短写
提供面向流I/O的对象为以下一个或多个类型要求建模:
- SyncReadStream,其中使用名为read_some()的成员函数执行同步读取操作
- AsyncReadStream,其中使用名为async_read_some()的成员函数执行异步读取操作
- SyncWriteStream,其中使用名为write_some()的成员函数执行同步写入操作
- AsyncWriteStream,其中使用名为async_write_some()的成员函数执行同步写入操作
面向流的I/O对象的示例包括
ip::tcp::socket
、ssl::stream<>
、posix::stream_descriptor
、windows::stream_handle
等。
也许混淆的地方在于您将其与iostream
接口进行比较,后者根本不是同一个概念(它来自标准库)。
对于如何为ssl流制作iostream
兼容的流包装器的问题,如果不更多地查阅文档并使用编译器,我就无法找到答案,而我目前还没有。
我认为这里的库还有改进的空间。如果你阅读ip::tcp::iostream
类(即basic_socket_iostream<ip::tcp>
),你会发现它有两个基类:
private detail::socket_iostream_base<ip::tcp>
public std::basic_iostream<char>
前者包含一个basic_socket_streambuf<ip::tcp>
(std::streambuf
和basic_socket<ip::tcp>
的派生类),其地址在构造时传递给后者。
在大多数情况下,basic_socket_streambuf<ip::tcp>
通过其basic_socket<ip::tcp>
基类执行实际的套接字操作。然而,有一个connect_to_endpoints()
成员函数跳过抽象,直接在socket().native_handle()
上从detail::socket_ops
命名空间调用几个低级函数。(这似乎是在Gitcommitb60e92b13e中引入的。)这些函数只能在TCP套接字上工作,即使该类是任何协议的模板。
在我发现这个问题之前,我将SSL支持集成为iostream/streambuf的计划是提供ssl
协议类和basic_socket<ssl>
模板专用化,以封装现有的ssl::context
和ssl::stream<ip::tcp::socket>
类。类似这样的东西(不会编译):
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/basic_socket.hpp>
#include <boost/asio/ssl.hpp>
namespace boost {
namespace asio {
namespace ip {
class ssl
: public tcp // for reuse (I'm lazy!)
{
public:
typedef basic_socket_iostream<ssl> iostream;
// more things as needed ...
};
} // namespace ip
template <>
class basic_socket<ip::ssl>
{
class SslContext
{
ssl::context ctx;
public:
SslContext() : ctx(ssl::context::sslv23_client)
{
ctx.set_options(ssl::context::default_workarounds);
ctx.set_default_verify_paths();
}
ssl::context & context() { return ctx; }
} sslContext;
ssl::stream<ip::tcp::socket> sslSocket;
public:
explicit basic_socket(const executor & ex)
: sslSocket(ex, sslContext.context())
{}
executor get_executor() noexcept
{
return sslSocket.lowest_layer().get_executor();
}
void connect(const ip::tcp::endpoint & endpoint_)
{
sslSocket.next_layer().connect(endpoint_);
sslSocket.lowest_layer().set_option(ip::tcp::no_delay(true));
sslSocket.set_verify_mode(ssl::verify_peer);
sslSocket.set_verify_callback(
ssl::rfc2818_verification("TODO: pass the domain here through the stream/streambuf somehow"));
sslSocket.handshake(ssl::stream<ip::tcp::socket>::client);
}
void close()
{
sslSocket.shutdown();
sslSocket.next_layer().close();
}
};
} // namespace asio
} // namespace boost
但由于设计问题,我还必须专门化basic_socket_streambuf<ip::ssl>
,以避免使用detail::socket_ops
例程。(我还应该避免将ssl
协议类注入boost::asio::ip
命名空间,但这是一个次要问题。)
我没有在这方面花太多时间,但这似乎是可行的。首先修复basic_socket_streambuf<>::connect_to_endpoints()
应该会有很大帮助。
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 实施具有 C++20 概念的配对概念
- 是否可以用"iostream"包装现有的TCP/OOpenSSL会话
- 需要从 istream 和 ostream 派生 iostream
- Python中的for循环与C++有何不同
- std::带有自定义缓冲区的 iostream 不允许我写入
- 在C++中释放内存期间,迭代器与指针有何不同
- 如何在C++中最好地实施"newtype"成语?
- 新的放置取决于 iostream
- 如何在MISRA C++之后实施CRTP
- 包含在 <initializer_list> <iostream>?
- 为什么在包含iostream时可以使用printf()?
- 所以我正在为我的学校作业练习继承,但我无法正确实施标题保护
- C++强制实施方法?
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- 如果 iostream 对象不可复制,为什么以下代码是合法的?
- shift_right() 打算如何在 C++20 中实施?
- 如何减少对 std::type_index 的实施?
- 为什么没有asio::ssl::iostream?(以及如何实施)
- 编写一个使用RC4流密码的C++iostream.如何优化我的实施