368 lines
9.8 KiB
Markdown
368 lines
9.8 KiB
Markdown
|
|
# Client-Native 重构前后对比
|
|||
|
|
|
|||
|
|
## 📊 项目结构对比
|
|||
|
|
|
|||
|
|
### 重构前(原版)
|
|||
|
|
```
|
|||
|
|
Client-Native/
|
|||
|
|
├── main.cpp (462行)
|
|||
|
|
│ ├── 证书常量定义 (1-100行)
|
|||
|
|
│ ├── 全局变量 (101-110行)
|
|||
|
|
│ ├── PrintSSLError() (111-120行)
|
|||
|
|
│ ├── LoadCertFromMemory() (121-140行)
|
|||
|
|
│ ├── LoadKeyFromMemory() (141-160行)
|
|||
|
|
│ ├── InitializeSSL() (161-250行)
|
|||
|
|
│ ├── InitializeWinsock() (251-260行)
|
|||
|
|
│ ├── ConnectToServer() (261-340行)
|
|||
|
|
│ ├── SendData() (341-360行)
|
|||
|
|
│ ├── ReceiveData() (361-390行)
|
|||
|
|
│ ├── Cleanup() (391-410行)
|
|||
|
|
│ ├── PrintMenu() (411-420行)
|
|||
|
|
│ └── main() (421-462行)
|
|||
|
|
├── pch.h
|
|||
|
|
└── pch.cpp
|
|||
|
|
|
|||
|
|
问题:
|
|||
|
|
❌ 单一文件包含所有功能
|
|||
|
|
❌ 全局变量(g_ssl_ctx, g_ssl, g_socket)
|
|||
|
|
❌ 难以单元测试
|
|||
|
|
❌ 代码复用困难
|
|||
|
|
❌ 职责不清晰
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 重构后(模块化)
|
|||
|
|
```
|
|||
|
|
Client-Native/
|
|||
|
|
├── 📄 main.cpp (122行)
|
|||
|
|
│ └── 应用程序主逻辑
|
|||
|
|
│ ├── 控制台初始化
|
|||
|
|
│ ├── 创建SSLClientConnection对象
|
|||
|
|
│ ├── 用户交互循环
|
|||
|
|
│ └── 命令处理
|
|||
|
|
│
|
|||
|
|
├── 📦 CertificateConfig (静态配置)
|
|||
|
|
│ ├── CertificateConfig.h
|
|||
|
|
│ └── CertificateConfig.cpp
|
|||
|
|
│ ├── GetClientCertificate()
|
|||
|
|
│ ├── GetClientPrivateKey()
|
|||
|
|
│ ├── GetCACertificate()
|
|||
|
|
│ └── GetKeyPassword()
|
|||
|
|
│
|
|||
|
|
├── 📦 CertificateManager (工具类)
|
|||
|
|
│ ├── CertificateManager.h
|
|||
|
|
│ └── CertificateManager.cpp
|
|||
|
|
│ ├── LoadCertificateFromMemory()
|
|||
|
|
│ ├── LoadPrivateKeyFromMemory()
|
|||
|
|
│ └── PrintSSLError()
|
|||
|
|
│
|
|||
|
|
├── 📦 SSLClientConnection (核心类)
|
|||
|
|
│ ├── SSLClientConnection.h
|
|||
|
|
│ └── SSLClientConnection.cpp
|
|||
|
|
│ ├── 构造/析构函数 (RAII)
|
|||
|
|
│ ├── Initialize()
|
|||
|
|
│ ├── Connect()
|
|||
|
|
│ ├── Send()
|
|||
|
|
│ ├── Receive()
|
|||
|
|
│ ├── Disconnect()
|
|||
|
|
│ ├── IsConnected()
|
|||
|
|
│ └── GetCipherSuite()
|
|||
|
|
│
|
|||
|
|
├── pch.h
|
|||
|
|
└── pch.cpp
|
|||
|
|
|
|||
|
|
优势:
|
|||
|
|
✅ 清晰的模块划分
|
|||
|
|
✅ 无全局变量
|
|||
|
|
✅ 易于单元测试
|
|||
|
|
✅ 代码高度复用
|
|||
|
|
✅ 职责明确
|
|||
|
|
✅ RAII自动资源管理
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📈 代码行数分布
|
|||
|
|
|
|||
|
|
### 原版
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────┐
|
|||
|
|
│ main.cpp (462行 = 100%) │
|
|||
|
|
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│
|
|||
|
|
└─────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 重构版
|
|||
|
|
```
|
|||
|
|
┌────────────────────────────┐
|
|||
|
|
│ main.cpp (122行 = 26%) │
|
|||
|
|
│ ▓▓▓▓▓▓▓▓ │
|
|||
|
|
├────────────────────────────┤
|
|||
|
|
│ CertificateConfig (100行) │
|
|||
|
|
│ ▓▓▓▓▓▓▓ │
|
|||
|
|
├────────────────────────────┤
|
|||
|
|
│ CertificateManager (80行) │
|
|||
|
|
│ ▓▓▓▓▓ │
|
|||
|
|
├────────────────────────────┤
|
|||
|
|
│ SSLClientConnection (220行)│
|
|||
|
|
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │
|
|||
|
|
└────────────────────────────┘
|
|||
|
|
总计: ~522行(包含头文件)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔄 调用流程对比
|
|||
|
|
|
|||
|
|
### 原版调用流程
|
|||
|
|
```
|
|||
|
|
main()
|
|||
|
|
├─> InitializeWinsock() // 全局变量初始化
|
|||
|
|
├─> InitializeSSL() // 全局 g_ssl_ctx
|
|||
|
|
├─> ConnectToServer() // 全局 g_ssl, g_socket
|
|||
|
|
├─> [主循环]
|
|||
|
|
│ ├─> SendData() // 使用全局 g_ssl
|
|||
|
|
│ └─> ReceiveData() // 使用全局 g_ssl
|
|||
|
|
└─> Cleanup() // 必须手动清理全局资源
|
|||
|
|
|
|||
|
|
问题:全局状态,函数间高度耦合
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 重构版调用流程
|
|||
|
|
```
|
|||
|
|
main()
|
|||
|
|
├─> SSLClientConnection client; // 对象创建
|
|||
|
|
├─> client.Initialize(...) // 封装的初始化
|
|||
|
|
│ ├─> CertificateConfig::Get...() // 获取证书
|
|||
|
|
│ └─> m_certManager.Load...() // 加载证书
|
|||
|
|
├─> client.Connect(...) // 封装的连接
|
|||
|
|
├─> [主循环]
|
|||
|
|
│ ├─> client.Send() // 成员方法
|
|||
|
|
│ └─> client.Receive() // 成员方法
|
|||
|
|
└─> ~SSLClientConnection() // 自动析构清理
|
|||
|
|
|
|||
|
|
优势:对象生命周期明确,无全局状态
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎯 设计原则对比
|
|||
|
|
|
|||
|
|
| 设计原则 | 原版 | 重构版 |
|
|||
|
|
|---------|------|--------|
|
|||
|
|
| **单一职责(SRP)** | ❌ main.cpp做所有事 | ✅ 每个类一个职责 |
|
|||
|
|
| **开闭原则(OCP)** | ❌ 修改困难 | ✅ 易于扩展 |
|
|||
|
|
| **依赖倒置(DIP)** | ❌ 依赖具体实现 | ✅ 依赖接口 |
|
|||
|
|
| **封装性** | ❌ 全局变量暴露 | ✅ 私有成员封装 |
|
|||
|
|
| **RAII** | ❌ 手动资源管理 | ✅ 自动资源管理 |
|
|||
|
|
|
|||
|
|
## 🧪 可测试性对比
|
|||
|
|
|
|||
|
|
### 原版 - 难以测试
|
|||
|
|
```cpp
|
|||
|
|
// 无法单独测试证书加载
|
|||
|
|
// 必须运行整个main()
|
|||
|
|
// 依赖全局状态
|
|||
|
|
|
|||
|
|
// 伪代码示例 - 无法实现
|
|||
|
|
TEST(CertificateTest, LoadCertificate) {
|
|||
|
|
// 无法测试,功能在main()里
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 重构版 - 易于测试
|
|||
|
|
```cpp
|
|||
|
|
// 可以单独测试每个模块
|
|||
|
|
|
|||
|
|
TEST(CertificateManagerTest, LoadCertificate) {
|
|||
|
|
CertificateManager mgr;
|
|||
|
|
X509* cert = mgr.LoadCertificateFromMemory(testCert);
|
|||
|
|
ASSERT_NE(nullptr, cert);
|
|||
|
|
X509_free(cert);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(SSLClientConnectionTest, Initialize) {
|
|||
|
|
SSLClientConnection client;
|
|||
|
|
bool result = client.Initialize(...);
|
|||
|
|
ASSERT_TRUE(result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
TEST(SSLClientConnectionTest, ConnectInvalidAddress) {
|
|||
|
|
SSLClientConnection client;
|
|||
|
|
client.Initialize(...);
|
|||
|
|
bool result = client.Connect("0.0.0.0", 99999);
|
|||
|
|
ASSERT_FALSE(result);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📦 代码复用对比
|
|||
|
|
|
|||
|
|
### 原版
|
|||
|
|
```cpp
|
|||
|
|
// 如果其他项目需要SSL客户端功能
|
|||
|
|
// 必须复制整个main.cpp
|
|||
|
|
// 然后手动提取需要的部分
|
|||
|
|
|
|||
|
|
// ❌ 无法复用
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 重构版
|
|||
|
|
```cpp
|
|||
|
|
// 其他项目可以直接使用类
|
|||
|
|
|
|||
|
|
// Project A: HTTP客户端
|
|||
|
|
class HttpsClient {
|
|||
|
|
private:
|
|||
|
|
SSLClientConnection m_sslConnection; // 复用!
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Project B: MQTT客户端
|
|||
|
|
class MqttSSLClient {
|
|||
|
|
private:
|
|||
|
|
SSLClientConnection m_sslConnection; // 复用!
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Project C: 简单证书工具
|
|||
|
|
void ValidateCertificate(const char* cert) {
|
|||
|
|
CertificateManager mgr; // 复用!
|
|||
|
|
X509* x509 = mgr.LoadCertificateFromMemory(cert);
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ 高度复用
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔐 资源管理对比
|
|||
|
|
|
|||
|
|
### 原版 - 手动管理(易出错)
|
|||
|
|
```cpp
|
|||
|
|
int main() {
|
|||
|
|
InitializeSSL(); // 分配资源
|
|||
|
|
ConnectToServer(); // 分配资源
|
|||
|
|
|
|||
|
|
// ... 很多代码 ...
|
|||
|
|
|
|||
|
|
// 如果中间return,资源泄漏!
|
|||
|
|
if (error) {
|
|||
|
|
return 1; // ❌ 忘记调用Cleanup()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Cleanup(); // 必须记得清理
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
风险:
|
|||
|
|
❌ 容易忘记清理
|
|||
|
|
❌ 异常路径泄漏
|
|||
|
|
❌ 早期return泄漏
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 重构版 - RAII自动管理
|
|||
|
|
```cpp
|
|||
|
|
int main() {
|
|||
|
|
{
|
|||
|
|
SSLClientConnection client; // 构造
|
|||
|
|
client.Initialize(...); // 分配资源
|
|||
|
|
client.Connect(...); // 分配资源
|
|||
|
|
|
|||
|
|
// ... 很多代码 ...
|
|||
|
|
|
|||
|
|
if (error) {
|
|||
|
|
return 1; // ✅ 析构函数自动清理
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 正常结束
|
|||
|
|
} // ✅ 离开作用域自动调用析构函数清理
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
优势:
|
|||
|
|
✅ 永不遗忘清理
|
|||
|
|
✅ 异常安全
|
|||
|
|
✅ 提前退出安全
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🚀 性能对比
|
|||
|
|
|
|||
|
|
| 指标 | 原版 | 重构版 | 说明 |
|
|||
|
|
|------|------|--------|------|
|
|||
|
|
| **运行时性能** | ⚡ | ⚡ | 相同(编译器内联优化) |
|
|||
|
|
| **内存使用** | 📊 | 📊 | 相同(相同的SSL对象) |
|
|||
|
|
| **编译时间** | 🕐 快 | 🕐 中等 | 重构版多文件略慢 |
|
|||
|
|
| **二进制大小** | 📦 | 📦 | 几乎相同 |
|
|||
|
|
|
|||
|
|
结论:**重构不影响运行时性能**
|
|||
|
|
|
|||
|
|
## 📚 学习曲线
|
|||
|
|
|
|||
|
|
### 原版
|
|||
|
|
```
|
|||
|
|
优点:
|
|||
|
|
✅ 一个文件看到所有代码
|
|||
|
|
✅ 流程清晰直观
|
|||
|
|
✅ 快速理解OpenSSL API
|
|||
|
|
|
|||
|
|
缺点:
|
|||
|
|
❌ 不符合工程实践
|
|||
|
|
❌ 难以维护
|
|||
|
|
❌ 不适合大型项目
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 重构版
|
|||
|
|
```
|
|||
|
|
优点:
|
|||
|
|
✅ 学习现代C++工程实践
|
|||
|
|
✅ 理解RAII和封装
|
|||
|
|
✅ 适合大型项目
|
|||
|
|
✅ 易于维护和扩展
|
|||
|
|
|
|||
|
|
缺点:
|
|||
|
|
❌ 需要理解多个文件
|
|||
|
|
❌ 需要理解类设计
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎓 推荐学习路径
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
A[开始学习] --> B[阅读原版main.cpp]
|
|||
|
|
B --> C[理解OpenSSL API]
|
|||
|
|
C --> D[阅读重构版]
|
|||
|
|
D --> E[理解模块化设计]
|
|||
|
|
E --> F[对比两个版本]
|
|||
|
|
F --> G[掌握工程实践]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
1. **第一步**: 阅读 `main.cpp.backup`(原版)
|
|||
|
|
- 快速理解 SSL 通信流程
|
|||
|
|
- 学习 OpenSSL API 使用
|
|||
|
|
|
|||
|
|
2. **第二步**: 阅读重构版各模块
|
|||
|
|
- CertificateConfig → 配置管理
|
|||
|
|
- CertificateManager → 工具类设计
|
|||
|
|
- SSLClientConnection → RAII和封装
|
|||
|
|
|
|||
|
|
3. **第三步**: 对比两个版本
|
|||
|
|
- 理解为什么要重构
|
|||
|
|
- 学习设计模式应用
|
|||
|
|
|
|||
|
|
## 📝 总结
|
|||
|
|
|
|||
|
|
### 原版适用场景
|
|||
|
|
- ✅ 快速原型开发
|
|||
|
|
- ✅ 学习OpenSSL API
|
|||
|
|
- ✅ 简单的一次性脚本
|
|||
|
|
- ✅ 代码量<500行
|
|||
|
|
|
|||
|
|
### 重构版适用场景
|
|||
|
|
- ✅ 生产环境项目
|
|||
|
|
- ✅ 团队协作开发
|
|||
|
|
- ✅ 需要单元测试
|
|||
|
|
- ✅ 需要代码复用
|
|||
|
|
- ✅ 大型项目(>1000行)
|
|||
|
|
|
|||
|
|
### 重构收益
|
|||
|
|
```
|
|||
|
|
可读性提升 ████████░░ 80%
|
|||
|
|
可维护性提升 ██████████ 100%
|
|||
|
|
可测试性提升 ██████████ 100%
|
|||
|
|
代码复用性 ██████████ 100%
|
|||
|
|
扩展性提升 █████████░ 90%
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
**结论**: 虽然重构后代码文件数量增加,但代码质量和工程实践显著提升,适合学习现代C++开发!
|