472 lines
17 KiB
Markdown
472 lines
17 KiB
Markdown
|
|
# Client-Native 架构设计文档
|
|||
|
|
|
|||
|
|
## 🏗️ 类图 (Class Diagram)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────┐
|
|||
|
|
│ <<static class>> │
|
|||
|
|
│ CertificateConfig │
|
|||
|
|
├─────────────────────────────┤
|
|||
|
|
│ + GetClientCertificate() │
|
|||
|
|
│ + GetClientPrivateKey() │
|
|||
|
|
│ + GetCACertificate() │
|
|||
|
|
│ + GetKeyPassword() │
|
|||
|
|
└─────────────────────────────┘
|
|||
|
|
△
|
|||
|
|
│ uses
|
|||
|
|
│
|
|||
|
|
┌─────────────────────────────┐ ┌─────────────────────────────┐
|
|||
|
|
│ CertificateManager │ │ SSLClientConnection │
|
|||
|
|
├─────────────────────────────┤ ├─────────────────────────────┤
|
|||
|
|
│ - (no state) │ │ - m_sslContext: SSL_CTX* │
|
|||
|
|
├─────────────────────────────┤ │ - m_ssl: SSL* │
|
|||
|
|
│ + LoadCertificateFromMemory()│◄───────┤ - m_socket: SOCKET │
|
|||
|
|
│ + LoadPrivateKeyFromMemory()│ uses │ - m_isConnected: bool │
|
|||
|
|
│ + PrintSSLError() │ │ - m_certManager: CertMgr │
|
|||
|
|
└─────────────────────────────┘ ├─────────────────────────────┤
|
|||
|
|
△ │ + Initialize() │
|
|||
|
|
│ uses │ + Connect() │
|
|||
|
|
│ │ + Send() │
|
|||
|
|
│ │ + Receive() │
|
|||
|
|
│ │ + Disconnect() │
|
|||
|
|
┌─────────────────────────────┐ │ + IsConnected() │
|
|||
|
|
│ main() │ │ + GetCipherSuite() │
|
|||
|
|
│ │ ├─────────────────────────────┤
|
|||
|
|
│ [Application Entry Point] │───────>│ - InitializeWinsock() │
|
|||
|
|
│ │ uses │ - Cleanup() │
|
|||
|
|
└─────────────────────────────┘ └─────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📊 模块关系图
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
main.cpp
|
|||
|
|
│
|
|||
|
|
├──► SSLClientConnection (主要依赖)
|
|||
|
|
│ │
|
|||
|
|
│ ├──► CertificateManager (内部依赖)
|
|||
|
|
│ │ │
|
|||
|
|
│ │ └──► OpenSSL API
|
|||
|
|
│ │
|
|||
|
|
│ └──► Winsock2 API
|
|||
|
|
│
|
|||
|
|
└──► CertificateConfig (直接依赖)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔄 对象生命周期
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌────── main() starts ──────┐
|
|||
|
|
│ │
|
|||
|
|
│ ┌──────────────────────┐ │
|
|||
|
|
│ │ SSLClientConnection │ │ <── 创建对象(栈上)
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ ┌────────────────┐ │ │
|
|||
|
|
│ │ │ CertManager │ │ │ <── 自动创建成员对象
|
|||
|
|
│ │ └────────────────┘ │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ [Initialize] │ │ <── 分配SSL资源
|
|||
|
|
│ │ └─> SSL_CTX* │ │
|
|||
|
|
│ │ └─> 加载证书 │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ [Connect] │ │ <── 分配Socket/SSL
|
|||
|
|
│ │ └─> SOCKET │ │
|
|||
|
|
│ │ └─> SSL* │ │
|
|||
|
|
│ │ └─> SSL握手 │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ [Send/Receive] │ │ <── 数据传输
|
|||
|
|
│ │ └─> SSL_write() │ │
|
|||
|
|
│ │ └─> SSL_read() │ │
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ [~Destructor] │ │ <── 自动清理
|
|||
|
|
│ │ └─> SSL_free() │ │
|
|||
|
|
│ │ └─> closesocket()│ │
|
|||
|
|
│ │ └─> SSL_CTX_free│ │
|
|||
|
|
│ └──────────────────────┘ │
|
|||
|
|
│ │
|
|||
|
|
└────── main() ends ────────┘
|
|||
|
|
(自动析构,无需手动清理)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎯 设计模式应用
|
|||
|
|
|
|||
|
|
### 1. RAII (Resource Acquisition Is Initialization)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
class SSLClientConnection {
|
|||
|
|
public:
|
|||
|
|
SSLClientConnection() // 构造函数 - 初始化状态
|
|||
|
|
: m_sslContext(nullptr)
|
|||
|
|
, m_ssl(nullptr)
|
|||
|
|
, m_socket(INVALID_SOCKET)
|
|||
|
|
, m_isConnected(false)
|
|||
|
|
{}
|
|||
|
|
|
|||
|
|
~SSLClientConnection() // 析构函数 - 自动清理资源
|
|||
|
|
{
|
|||
|
|
Cleanup(); // 释放SSL、Socket等资源
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 禁止拷贝(避免资源重复释放)
|
|||
|
|
SSLClientConnection(const SSLClientConnection&) = delete;
|
|||
|
|
SSLClientConnection& operator=(const SSLClientConnection&) = delete;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
使用:
|
|||
|
|
{
|
|||
|
|
SSLClientConnection client; // 自动调用构造函数
|
|||
|
|
client.Initialize(...);
|
|||
|
|
client.Connect(...);
|
|||
|
|
// ...
|
|||
|
|
} // ← 离开作用域,自动调用析构函数清理
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. Static Factory (静态工厂)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
class CertificateConfig {
|
|||
|
|
public:
|
|||
|
|
// 静态方法,无需实例化
|
|||
|
|
static const char* GetClientCertificate() {
|
|||
|
|
return g_clientCert;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
// 私有构造函数,防止实例化
|
|||
|
|
CertificateConfig() = default;
|
|||
|
|
~CertificateConfig() = default;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
使用:
|
|||
|
|
const char* cert = CertificateConfig::GetClientCertificate(); // 直接调用
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. Manager Pattern (管理器模式)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
class CertificateManager {
|
|||
|
|
public:
|
|||
|
|
// 无状态的工具方法
|
|||
|
|
X509* LoadCertificateFromMemory(const char* certPem);
|
|||
|
|
EVP_PKEY* LoadPrivateKeyFromMemory(const char* keyPem, ...);
|
|||
|
|
static void PrintSSLError(const char* message);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
使用:
|
|||
|
|
CertificateManager mgr;
|
|||
|
|
X509* cert = mgr.LoadCertificateFromMemory(certData);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. Facade Pattern (外观模式)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
// SSLClientConnection 提供简化的接口
|
|||
|
|
// 隐藏底层 OpenSSL + Winsock 的复杂性
|
|||
|
|
|
|||
|
|
class SSLClientConnection {
|
|||
|
|
public:
|
|||
|
|
// 简单易用的接口
|
|||
|
|
bool Initialize(...); // 内部处理 SSL_CTX、证书加载等
|
|||
|
|
bool Connect(...); // 内部处理 socket、SSL握手等
|
|||
|
|
bool Send(...); // 内部处理 SSL_write
|
|||
|
|
int Receive(...); // 内部处理 SSL_read
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
// 隐藏复杂的内部实现
|
|||
|
|
bool InitializeWinsock();
|
|||
|
|
void Cleanup();
|
|||
|
|
// ...
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📐 架构层次
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────┐
|
|||
|
|
│ 应用层 (Application Layer) │ ← main.cpp
|
|||
|
|
│ - 用户交互 │
|
|||
|
|
│ - 命令处理 │
|
|||
|
|
│ - 主循环控制 │
|
|||
|
|
└─────────────────────────────────────────┘
|
|||
|
|
↓ uses
|
|||
|
|
┌─────────────────────────────────────────┐
|
|||
|
|
│ 业务层 (Business Layer) │ ← SSLClientConnection
|
|||
|
|
│ - SSL连接管理 │
|
|||
|
|
│ - 数据发送/接收 │
|
|||
|
|
│ - 连接状态管理 │
|
|||
|
|
└─────────────────────────────────────────┘
|
|||
|
|
↓ uses
|
|||
|
|
┌─────────────────────────────────────────┐
|
|||
|
|
│ 工具层 (Utility Layer) │ ← CertificateManager
|
|||
|
|
│ - 证书加载 │
|
|||
|
|
│ - 错误处理 │
|
|||
|
|
│ - 通用工具 │
|
|||
|
|
└─────────────────────────────────────────┘
|
|||
|
|
↓ uses
|
|||
|
|
┌─────────────────────────────────────────┐
|
|||
|
|
│ 数据层 (Data Layer) │ ← CertificateConfig
|
|||
|
|
│ - 证书数据 │
|
|||
|
|
│ - 配置数据 │
|
|||
|
|
└─────────────────────────────────────────┘
|
|||
|
|
↓ uses
|
|||
|
|
┌─────────────────────────────────────────┐
|
|||
|
|
│ 系统层 (System Layer) │
|
|||
|
|
│ - OpenSSL API │
|
|||
|
|
│ - Winsock2 API │
|
|||
|
|
│ - Windows API │
|
|||
|
|
└─────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔐 数据流图
|
|||
|
|
|
|||
|
|
### 初始化流程
|
|||
|
|
```
|
|||
|
|
main()
|
|||
|
|
│
|
|||
|
|
├─> CertificateConfig::GetClientCertificate()
|
|||
|
|
│ │
|
|||
|
|
│ └─> return g_clientCert
|
|||
|
|
│
|
|||
|
|
├─> SSLClientConnection::Initialize(cert, key, ca, pwd)
|
|||
|
|
│ │
|
|||
|
|
│ ├─> SSL_CTX_new(TLS_client_method())
|
|||
|
|
│ │
|
|||
|
|
│ ├─> CertificateManager::LoadCertificateFromMemory(ca)
|
|||
|
|
│ │ │
|
|||
|
|
│ │ ├─> BIO_new_mem_buf()
|
|||
|
|
│ │ ├─> PEM_read_bio_X509()
|
|||
|
|
│ │ └─> return X509*
|
|||
|
|
│ │
|
|||
|
|
│ ├─> SSL_CTX_use_certificate()
|
|||
|
|
│ │
|
|||
|
|
│ └─> SSL_CTX_use_PrivateKey()
|
|||
|
|
│
|
|||
|
|
└─> SSLClientConnection::Connect(address, port)
|
|||
|
|
│
|
|||
|
|
├─> socket() → SOCKET
|
|||
|
|
├─> connect() → TCP连接
|
|||
|
|
├─> SSL_new() → SSL*
|
|||
|
|
├─> SSL_set_fd()
|
|||
|
|
└─> SSL_connect() → SSL握手
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 数据传输流程
|
|||
|
|
```
|
|||
|
|
main() [用户输入 "1"]
|
|||
|
|
│
|
|||
|
|
├─> SSLClientConnection::Send("hello")
|
|||
|
|
│ │
|
|||
|
|
│ └─> SSL_write(m_ssl, "hello", 5)
|
|||
|
|
│ │
|
|||
|
|
│ └─> [加密] → 网络发送
|
|||
|
|
│
|
|||
|
|
└─> SSLClientConnection::Receive(buffer, size)
|
|||
|
|
│
|
|||
|
|
└─> SSL_read(m_ssl, buffer, size)
|
|||
|
|
│
|
|||
|
|
└─> 网络接收 → [解密] → buffer
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 💾 内存布局
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Stack (栈):
|
|||
|
|
┌──────────────────────────────────────┐
|
|||
|
|
│ main() 函数帧 │
|
|||
|
|
│ ├─ SSLClientConnection client; │ <── 完整对象
|
|||
|
|
│ │ ├─ m_sslContext: SSL_CTX* │ <── 指针(8字节)
|
|||
|
|
│ │ ├─ m_ssl: SSL* │ <── 指针(8字节)
|
|||
|
|
│ │ ├─ m_socket: SOCKET │ <── 句柄(8字节)
|
|||
|
|
│ │ ├─ m_isConnected: bool │ <── 布尔(1字节)
|
|||
|
|
│ │ └─ m_certManager: CertMgr │ <── 空对象(1字节)
|
|||
|
|
│ │ │
|
|||
|
|
│ └─ char receiveBuffer[1024]; │ <── 缓冲区
|
|||
|
|
└──────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
Heap (堆):
|
|||
|
|
┌──────────────────────────────────────┐
|
|||
|
|
│ SSL_CTX 结构体 ←─ m_sslContext │
|
|||
|
|
│ SSL 结构体 ←─ m_ssl │
|
|||
|
|
│ X509 证书对象 │
|
|||
|
|
│ EVP_PKEY 私钥对象 │
|
|||
|
|
│ ... │
|
|||
|
|
└──────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
析构时自动释放所有堆内存
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📊 编译依赖关系
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
main.cpp
|
|||
|
|
├─ #include "pch.h"
|
|||
|
|
├─ #include "CertificateConfig.h"
|
|||
|
|
└─ #include "SSLClientConnection.h"
|
|||
|
|
|
|||
|
|
SSLClientConnection.cpp
|
|||
|
|
├─ #include "pch.h"
|
|||
|
|
├─ #include "SSLClientConnection.h"
|
|||
|
|
└─ #include "CertificateManager.h"
|
|||
|
|
|
|||
|
|
CertificateManager.cpp
|
|||
|
|
├─ #include "pch.h"
|
|||
|
|
└─ #include "CertificateManager.h"
|
|||
|
|
|
|||
|
|
CertificateConfig.cpp
|
|||
|
|
├─ #include "pch.h"
|
|||
|
|
└─ #include "CertificateConfig.h"
|
|||
|
|
|
|||
|
|
pch.h (预编译头)
|
|||
|
|
├─ #include <winsock2.h>
|
|||
|
|
├─ #include <windows.h>
|
|||
|
|
├─ #include <openssl/ssl.h>
|
|||
|
|
├─ #include <openssl/err.h>
|
|||
|
|
└─ ... (其他系统头文件)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🧪 单元测试架构(未来扩展)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
// 伪代码示例
|
|||
|
|
|
|||
|
|
TEST_SUITE(CertificateConfigTest) {
|
|||
|
|
TEST(GetClientCertificate_ReturnsValidCert) {
|
|||
|
|
const char* cert = CertificateConfig::GetClientCertificate();
|
|||
|
|
ASSERT_NOT_NULL(cert);
|
|||
|
|
ASSERT_TRUE(strstr(cert, "BEGIN CERTIFICATE"));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST_SUITE(CertificateManagerTest) {
|
|||
|
|
TEST(LoadCertificateFromMemory_ValidCert_ReturnsX509) {
|
|||
|
|
CertificateManager mgr;
|
|||
|
|
X509* cert = mgr.LoadCertificateFromMemory(validCert);
|
|||
|
|
ASSERT_NOT_NULL(cert);
|
|||
|
|
X509_free(cert);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(LoadCertificateFromMemory_InvalidCert_ReturnsNull) {
|
|||
|
|
CertificateManager mgr;
|
|||
|
|
X509* cert = mgr.LoadCertificateFromMemory("invalid");
|
|||
|
|
ASSERT_NULL(cert);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST_SUITE(SSLClientConnectionTest) {
|
|||
|
|
TEST(Initialize_ValidCerts_ReturnsTrue) {
|
|||
|
|
SSLClientConnection client;
|
|||
|
|
bool result = client.Initialize(
|
|||
|
|
validCert, validKey, validCA, "password"
|
|||
|
|
);
|
|||
|
|
ASSERT_TRUE(result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(Connect_InvalidAddress_ReturnsFalse) {
|
|||
|
|
SSLClientConnection client;
|
|||
|
|
client.Initialize(...);
|
|||
|
|
bool result = client.Connect("0.0.0.0", 99999);
|
|||
|
|
ASSERT_FALSE(result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(Send_NotConnected_ReturnsFalse) {
|
|||
|
|
SSLClientConnection client;
|
|||
|
|
bool result = client.Send("hello");
|
|||
|
|
ASSERT_FALSE(result);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔧 配置和扩展点
|
|||
|
|
|
|||
|
|
### 扩展点 1: 支持配置文件
|
|||
|
|
```cpp
|
|||
|
|
// 未来可以添加
|
|||
|
|
class ConfigReader {
|
|||
|
|
public:
|
|||
|
|
ServerConfig ReadFromFile(const std::string& path);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 使用
|
|||
|
|
ConfigReader reader;
|
|||
|
|
ServerConfig config = reader.ReadFromFile("config.json");
|
|||
|
|
client.Connect(config.address, config.port);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 扩展点 2: 日志系统
|
|||
|
|
```cpp
|
|||
|
|
// 未来可以添加
|
|||
|
|
class Logger {
|
|||
|
|
public:
|
|||
|
|
static void Info(const std::string& msg);
|
|||
|
|
static void Error(const std::string& msg);
|
|||
|
|
static void Debug(const std::string& msg);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 在SSLClientConnection中使用
|
|||
|
|
Logger::Info("SSL握手成功");
|
|||
|
|
Logger::Error("连接失败");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 扩展点 3: 异步IO
|
|||
|
|
```cpp
|
|||
|
|
// 未来可以添加
|
|||
|
|
class AsyncSSLClient : public SSLClientConnection {
|
|||
|
|
public:
|
|||
|
|
std::future<bool> ConnectAsync(const char* addr, int port);
|
|||
|
|
std::future<bool> SendAsync(const std::string& data);
|
|||
|
|
std::future<int> ReceiveAsync(char* buffer, int size);
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📈 性能考虑
|
|||
|
|
|
|||
|
|
| 方面 | 原版 | 重构版 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| **函数调用开销** | 直接调用 | 通过对象调用 | 编译器内联优化,无差异 |
|
|||
|
|
| **内存使用** | 全局变量 | 栈上对象 | 相同(对象很小) |
|
|||
|
|
| **缓存友好性** | 中等 | 好 | 相关数据集中在对象内 |
|
|||
|
|
| **编译优化** | 好 | 好 | 现代编译器优化效果相同 |
|
|||
|
|
|
|||
|
|
**结论**: 重构对运行时性能几乎无影响。
|
|||
|
|
|
|||
|
|
## 📚 代码度量
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
复杂度 (Cyclomatic Complexity):
|
|||
|
|
- 原版 main(): ~25 (高复杂度)
|
|||
|
|
- 重构版 main(): ~8 (低复杂度)
|
|||
|
|
- SSLClientConnection::Connect(): ~12 (中等复杂度)
|
|||
|
|
- CertificateManager::Load*(): ~5 (低复杂度)
|
|||
|
|
|
|||
|
|
耦合度 (Coupling):
|
|||
|
|
- 原版: 高耦合(全局变量)
|
|||
|
|
- 重构版: 低耦合(依赖注入)
|
|||
|
|
|
|||
|
|
内聚度 (Cohesion):
|
|||
|
|
- 原版: 低内聚(功能分散)
|
|||
|
|
- 重构版: 高内聚(功能集中)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎓 学习建议
|
|||
|
|
|
|||
|
|
### 初学者
|
|||
|
|
1. 先理解原版 `main.cpp.backup`
|
|||
|
|
2. 运行并测试原版代码
|
|||
|
|
3. 阅读重构版各模块
|
|||
|
|
4. 对比理解设计改进
|
|||
|
|
|
|||
|
|
### 中级开发者
|
|||
|
|
1. 分析类的职责划分
|
|||
|
|
2. 理解RAII资源管理
|
|||
|
|
3. 学习设计模式应用
|
|||
|
|
4. 尝试添加单元测试
|
|||
|
|
|
|||
|
|
### 高级开发者
|
|||
|
|
1. 评估架构设计
|
|||
|
|
2. 考虑性能优化
|
|||
|
|
3. 扩展功能(如异步IO)
|
|||
|
|
4. 改进错误处理
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
**总结**: 这个重构展示了从"过程式编程"到"面向对象编程"的完整转变,是学习现代C++工程实践的绝佳案例。
|