我回答这个问题比较晚,但我希望这对其他人有帮助。 Sam 的回答包含了一个想法的萌芽,但在我看来还远远不够。
这个想法源于观察到 asio 将 SSL 套接字包装在流中。这个解决方案所做的只是它类似地包装了非 SSL 套接字。
在 SSL 和非 SSL 套接字之间拥有统一的外部接口的预期结果是通过三个类完成的。一、base,有效定义了接口:
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));
}
};
两个子类包装 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();
}
};
和
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();
}
};
每次调用 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));
注意 Socket 是作为指针存储的。我想不出还有什么办法可以隐藏多态性。
惩罚(我认为不太好)是用于获取非 SSL 套接字的额外间接级别。