我正在将库转换为Boost.Asio(到目前为止工作得非常好),但我在设计决策方面遇到了一些绊脚石.
Boost.Asio提供对SSL的支持,但boost::asio::ssl::stream<boost::asio::ip::tcp::socket>必须为套接字使用类型.我的库可以选择连接到SSL服务器或正常连接,所以我创建了一个带有两个套接字的类,如下所示:
class client : public boost::enable_shared_from_this<client>
{
public:
client(boost::asio::io_service & io_service, boost::asio::ssl::context & context) : socket_(io_service), secureSocket_(io_service, context) {}
private:
boost::asio::ip::tcp::socket socket_;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> secureSocket_;
};
Run Code Online (Sandbox Code Playgroud)
并且有一堆参考的处理程序socket_.(例如,我有socket_.is_open()几个地方,需要成为secureSocket_.lowest_layer().is_open()另一个插座.)
任何人都可以建议最好的方法来解决这个问题吗?我宁愿不为此目的创建一个单独的类,因为这意味着要复制很多代码.
编辑:我改写了我原来的问题,因为我误解了OpenSSL函数的用途.
Nic*_*ole 18
我回答这个问题的时间比较晚,但我希望这会对其他人有所帮助.Sam的回答包含了一个想法的细节,但在我看来并没有放弃.
这个想法来自于asio在流中包装SSL套接字的观察结果.所有这个解决方案都是类似地包装非SSL套接字.
在SSL和非SSL套接字之间具有统一外部接口的期望结果是使用三个类完成的.一,基础,有效地定义了接口:
class Socket {
public:
virtual boost::asio::ip::tcp::socket &getSocketForAsio() = 0;
static Socket* create(boost::asio::io_service& iIoService, boost::asio::ssl::context *ipSslContext) {
// Obviously this has to be in a separate source file since it makes reference to subclasses
if (ipSslContext == nullptr) {
return new NonSslSocket(iIoService);
}
return new SslSocket(iIoService, *ipSslContext);
}
size_t _read(void *ipData, size_t iLength) {
return boost::asio::read(getSocketForAsio(), boost::asio::buffer(ipData, iLength));
}
size_t _write(const void *ipData, size_t iLength) {
return boost::asio::write(getSocketForAsio(), boost::asio::buffer(ipData, iLength));
}
};
Run Code Online (Sandbox Code Playgroud)
两个子类包装SSL和非SSL套接字.
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SslSocket_t;
class SslSocket: public Socket, private SslSocket_t {
public:
SslSocket(boost::asio::io_service& iIoService, boost::asio::ssl::context &iSslContext) :
SslSocket_t(iIoService, iSslContext) {
}
private:
boost::asio::ip::tcp::socket &getSocketForAsio() {
return next_layer();
}
};
Run Code Online (Sandbox Code Playgroud)
和
class NonSslSocket: public Socket, private Socket_t {
public:
NonSslSocket(boost::asio::io_service& iIoService) :
Socket_t(iIoService) {
}
private:
boost::asio::ip::tcp::socket &getSocketForAsio() {
return next_layer();
}
};
Run Code Online (Sandbox Code Playgroud)
每次调用asio函数时都使用getSocketForAsio(),而不是传递对Socket对象的引用.例如:
boost::asio::async_read(pSocket->getSocketForAsio(),
boost::asio::buffer(&buffer, sizeof(buffer)),
boost::bind(&Connection::handleRead,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
Run Code Online (Sandbox Code Playgroud)
请注意,Socket存储为指针.我想不出怎样才能隐藏多态.
惩罚(我认为不太好)是用于获取非SSL套接字的额外间接级别.
Sam*_*ler 14
有几种方法可以做到这一点.在过去,我做过类似的事情
if ( sslEnabled )
boost::asio::async_write( secureSocket_ );
} else {
boost::asio::async_write( secureSocket_.lowest_layer() );
}
Run Code Online (Sandbox Code Playgroud)
通过大量的if/else陈述,这很快就会变得混乱.您还可以创建一个抽象类(伪代码 - 过度简化)
class Socket
{
public:
virtual void connect( ... );
virtual void accept( ... );
virtual void async_write( ... );
virtual void async_read( ... );
private:
boost::asio::ip::tcp::socket socket_;
};
Run Code Online (Sandbox Code Playgroud)
然后创建一个派生类SecureSocket来操作secureSocket_而不是socket_.我不认为它会被重复了很多代码,它可能比清洁if/else每当你需要async_read或async_write.
当然,问题是 tcp::socket 和 ssl“socket”不共享任何共同的祖先。但是,打开套接字后使用套接字的大多数函数都共享完全相同的语法。因此,最干净的解决方案是使用模板。
template <typename SocketType>
void doStuffWithOpenSocket(SocketType socket) {
boost::asio::write(socket, ...);
boost::asio::read(socket, ...);
boost::asio::read_until(socket, ...);
// etc...
}
Run Code Online (Sandbox Code Playgroud)
此函数可与普通 tcp::sockets 以及安全 SSL 套接字一起使用:
boost::asio::ip::tcp::socket socket_;
// socket_ opened normally ...
doStuffWithOpenSocket<boost::asio::ip::tcp::socket>(socket_); // works!
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> secureSocket_;
// secureSocket_ opened normally (including handshake) ...
doStuffWithOpenSocket(secureSocket_); // also works, with (different) implicit instantiation!
// shutdown the ssl socket when done ...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9366 次 |
| 最近记录: |