基于OpenSSL的多客户端加密通信系统
1. 系统概述
本系统实现了一个基于OpenSSL的多客户端加密通信系统,具有以下特点:
- 使用SSL/TLS进行加密通信
- 支持多客户端并发连接
- 使用多线程处理客户端请求
- 提供安全的握手过程和数据传输
2. 系统架构
2.1 文件结构
03.加密通信系统/
├── SSLServer.h # 服务器类声明
├── SSLServer.cpp # 服务器类实现
├── SSLClient.h # 客户端类声明
├── SSLClient.cpp # 客户端类实现
├── server_main.cpp # 服务器主程序
├── client_main.cpp # 客户端主程序
├── Makefile # 编译配置文件
├── server.crt # 服务器证书
└── server.key # 服务器私钥
2.2 主要类设计
SSLServer类
- 功能:处理多客户端连接和SSL通信
- 主要方法:
start(): 启动服务器stop(): 停止服务器handleClient(): 处理客户端连接initSSL(): 初始化SSL上下文
SSLClient类
- 功能:实现客户端SSL通信
- 主要方法:
connect(): 连接到服务器send(): 发送数据receive(): 接收数据disconnect(): 断开连接
2.2 代码实现
SSLServer.h
#ifndef SSL_SERVER_H
#define SSL_SERVER_H
#include <string>
#include <vector>
#include <thread>
#include <mutex>
#include <memory>
#include <openssl/ssl.h>
#include <openssl/err.h>
class SSLServer {
public:
// 构造函数,初始化端口号
SSLServer(int port);
// 析构函数,确保资源正确释放
~SSLServer();
// 启动服务器
bool start();
// 停止服务器
void stop();
private:
// 初始化SSL上下文
bool initSSL();
// 处理客户端连接
void handleClient(int clientSocket);
// 清理SSL资源
void cleanupSSL();
int port_; // 服务器端口
int serverSocket_; // 服务器socket
bool running_; // 服务器运行状态
SSL_CTX* ctx_; // SSL上下文
std::vector<std::thread> clientThreads_; // 客户端线程列表
std::mutex mutex_; // 互斥锁,保护共享资源
};
#endif // SSL_SERVER_H
SSLServer.cpp
#include "SSLServer.h"
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// 构造函数:初始化OpenSSL库和成员变量
SSLServer::SSLServer(int port) : port_(port), serverSocket_(-1), running_(false), ctx_(nullptr) {
// 初始化OpenSSL库
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
}
// 析构函数:确保资源正确释放
SSLServer::~SSLServer() {
stop();
cleanupSSL();
}
// 初始化SSL上下文
bool SSLServer::initSSL() {
// 创建SSL上下文,使用TLS服务器方法
ctx_ = SSL_CTX_new(TLS_server_method());
if (!ctx_) {
std::cerr << "Error creating SSL context" << std::endl;
return false;
}
// 加载服务器证书
if (SSL_CTX_use_certificate_file(ctx_, "server.crt", SSL_FILETYPE_PEM) <= 0) {
std::cerr << "Error loading certificate" << std::endl;
return false;
}
// 加载服务器私钥
if (SSL_CTX_use_PrivateKey_file(ctx_, "server.key", SSL_FILETYPE_PEM) <= 0) {
std::cerr << "Error loading private key" << std::endl;
return false;
}
return true;
}
// 启动服务器
bool SSLServer::start() {
if (!initSSL()) {
return false;
}
// 创建服务器socket
serverSocket_ = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket_ < 0) {
std::cerr << "Error creating socket" << std::endl;
return false;
}
// 设置socket选项,允许地址重用
int opt = 1;
if (setsockopt(serverSocket_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
std::cerr << "Error setting socket options" << std::endl;
return false;
}
// 绑定地址和端口
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(port_);
if (bind(serverSocket_, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
std::cerr << "Error binding socket" << std::endl;
return false;
}
// 开始监听连接
if (listen(serverSocket_, SOMAXCONN) < 0) {
std::cerr << "Error listening on socket" << std::endl;
return false;
}
running_ = true;
std::cout << "Server started on port " << port_ << std::endl;
// 主循环:接受客户端连接
while (running_) {
struct sockaddr_in clientAddr;
socklen_t clientLen = sizeof(clientAddr);
int clientSocket = accept(serverSocket_, (struct sockaddr*)&clientAddr, &clientLen);
if (clientSocket < 0) {
std::cerr << "Error accepting connection" << std::endl;
continue;
}
std::cout << "New client connected from " << inet_ntoa(clientAddr.sin_addr) << std::endl;
// 为每个客户端创建新线程
std::lock_guard<std::mutex> lock(mutex_);
clientThreads_.emplace_back(&SSLServer::handleClient, this, clientSocket);
}
return true;
}
// 处理客户端连接
void SSLServer::handleClient(int clientSocket) {
// 创建SSL连接
SSL* ssl = SSL_new(ctx_);
SSL_set_fd(ssl, clientSocket);
// 执行SSL握手
if (SSL_accept(ssl) <= 0) {
std::cerr << "SSL handshake failed" << std::endl;
SSL_free(ssl);
close(clientSocket);
return;
}
std::cout << "SSL connection established" << std::endl;
// 处理客户端数据
char buffer[1024];
while (running_) {
int bytes = SSL_read(ssl, buffer, sizeof(buffer) - 1);
if (bytes <= 0) {
break;
}
buffer[bytes] = '\0';
std::cout << "Received: " << buffer << std::endl;
// 发送响应
std::string response = "Server received: " + std::string(buffer);
SSL_write(ssl, response.c_str(), response.length());
}
// 清理SSL连接
SSL_shutdown(ssl);
SSL_free(ssl);
close(clientSocket);
}
// 停止服务器
void SSLServer::stop() {
running_ = false;
// 等待所有客户端线程结束
for (auto& thread : clientThreads_) {
if (thread.joinable()) {
thread.join();
}
}
clientThreads_.clear();
if (serverSocket_ >= 0) {
close(serverSocket_);
serverSocket_ = -1;
}
}
// 清理SSL资源
void SSLServer::cleanupSSL() {
if (ctx_) {
SSL_CTX_free(ctx_);
ctx_ = nullptr;
}
EVP_cleanup();
}
SSLClient.h
#ifndef SSL_CLIENT_H
#define SSL_CLIENT_H
#include <string>
#include <openssl/ssl.h>
#include <openssl/err.h>
class SSLClient {
public:
// 构造函数,初始化主机和端口
SSLClient(const std::string& host, int port);
// 析构函数,确保资源正确释放
~SSLClient();
// 连接到服务器
bool connect();
// 发送数据
bool send(const std::string& message);
// 接收数据
std::string receive();
// 断开连接
void disconnect();
private:
// 初始化SSL
bool initSSL();
// 清理SSL资源
void cleanupSSL();
std::string host_; // 服务器主机名
int port_; // 服务器端口
int socket_; // 客户端socket
SSL_CTX* ctx_; // SSL上下文
SSL* ssl_; // SSL连接
bool connected_; // 连接状态
};
#endif // SSL_CLIENT_H
SSLClient.cpp
#include "SSLClient.h"
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
// 构造函数:初始化OpenSSL库和成员变量
SSLClient::SSLClient(const std::string& host, int port)
: host_(host), port_(port), socket_(-1), ctx_(nullptr), ssl_(nullptr), connected_(false) {
// 初始化OpenSSL库
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
}
// 析构函数:确保资源正确释放
SSLClient::~SSLClient() {
disconnect();
cleanupSSL();
}
// 初始化SSL
bool SSLClient::initSSL() {
// 创建SSL上下文,使用TLS客户端方法
ctx_ = SSL_CTX_new(TLS_client_method());
if (!ctx_) {
std::cerr << "Error creating SSL context" << std::endl;
return false;
}
return true;
}
// 连接到服务器
bool SSLClient::connect() {
if (!initSSL()) {
return false;
}
// 创建socket
socket_ = socket(AF_INET, SOCK_STREAM, 0);
if (socket_ < 0) {
std::cerr << "Error creating socket" << std::endl;
return false;
}
// 解析主机名
struct hostent* server = gethostbyname(host_.c_str());
if (!server) {
std::cerr << "Error resolving hostname" << std::endl;
return false;
}
// 设置服务器地址
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
memcpy(&serverAddr.sin_addr.s_addr, server->h_addr, server->h_length);
serverAddr.sin_port = htons(port_);
// 连接到服务器
if (::connect(socket_, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
std::cerr << "Error connecting to server" << std::endl;
return false;
}
// 创建SSL连接
ssl_ = SSL_new(ctx_);
SSL_set_fd(ssl_, socket_);
// 执行SSL握手
if (SSL_connect(ssl_) != 1) {
std::cerr << "SSL handshake failed" << std::endl;
return false;
}
std::cout << "Connected to server with " << SSL_get_cipher(ssl_) << " encryption" << std::endl;
connected_ = true;
return true;
}
// 发送数据
bool SSLClient::send(const std::string& message) {
if (!connected_) {
return false;
}
int bytes = SSL_write(ssl_, message.c_str(), message.length());
return bytes > 0;
}
// 接收数据
std::string SSLClient::receive() {
if (!connected_) {
return "";
}
char buffer[1024];
int bytes = SSL_read(ssl_, buffer, sizeof(buffer) - 1);
if (bytes <= 0) {
return "";
}
buffer[bytes] = '\0';
return std::string(buffer);
}
// 断开连接
void SSLClient::disconnect() {
if (connected_) {
SSL_shutdown(ssl_);
SSL_free(ssl_);
ssl_ = nullptr;
close(socket_);
socket_ = -1;
connected_ = false;
}
}
// 清理SSL资源
void SSLClient::cleanupSSL() {
if (ctx_) {
SSL_CTX_free(ctx_);
ctx_ = nullptr;
}
EVP_cleanup();
}
server_main.cpp
#include "SSLServer.h"
#include <iostream>
#include <csignal>
// 全局服务器指针,用于信号处理
SSLServer* server = nullptr;
// 信号处理函数
void signalHandler(int signum) {
if (server) {
std::cout << "\nShutting down server..." << std::endl;
server->stop();
}
exit(signum);
}
int main(int argc, char* argv[]) {
// 检查命令行参数
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <port>" << std::endl;
return 1;
}
int port = std::stoi(argv[1]);
// 注册信号处理函数
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);
// 创建并启动服务器
server = new SSLServer(port);
if (!server->start()) {
std::cerr << "Failed to start server" << std::endl;
delete server;
return 1;
}
// 等待服务器停止
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
delete server;
return 0;
}
client_main.cpp
#include "SSLClient.h"
#include <iostream>
#include <string>
#include <csignal>
// 全局客户端指针,用于信号处理
SSLClient* client = nullptr;
// 信号处理函数
void signalHandler(int signum) {
if (client) {
std::cout << "\nDisconnecting..." << std::endl;
client->disconnect();
}
exit(signum);
}
int main(int argc, char* argv[]) {
// 检查命令行参数
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " <host> <port>" << std::endl;
return 1;
}
std::string host = argv[1];
int port = std::stoi(argv[2]);
// 注册信号处理函数
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);
// 创建并连接客户端
client = new SSLClient(host, port);
if (!client->connect()) {
std::cerr << "Failed to connect to server" << std::endl;
delete client;
return 1;
}
// 交互式发送消息
std::string message;
while (true) {
std::cout << "Enter message (or 'quit' to exit): ";
std::getline(std::cin, message);
if (message == "quit") {
break;
}
if (!client->send(message)) {
std::cerr << "Failed to send message" << std::endl;
break;
}
std::string response = client->receive();
if (response.empty()) {
std::cerr << "Failed to receive response" << std::endl;
break;
}
std::cout << "Server response: " << response << std::endl;
}
client->disconnect();
delete client;
return 0;
}
Makefile
# 编译器设置
CXX = g++
CXXFLAGS = -std=c++17 -Wall -Wextra
# OpenSSL库
OPENSSL_LIBS = -lssl -lcrypto -lpthread
# 目标文件
SERVER_OBJS = server_main.o SSLServer.o
CLIENT_OBJS = client_main.o SSLClient.o
# 可执行文件
SERVER = ssl_server
CLIENT = ssl_client
# 默认目标
all: $(SERVER) $(CLIENT)
# 编译服务器
$(SERVER): $(SERVER_OBJS)
$(CXX) $(CXXFLAGS) -o $@ $^ $(OPENSSL_LIBS)
# 编译客户端
$(CLIENT): $(CLIENT_OBJS)
$(CXX) $(CXXFLAGS) -o $@ $^ $(OPENSSL_LIBS)
# 编译规则
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $<
# 清理
clean:
rm -f $(SERVER) $(CLIENT) *.o
# 重新编译
rebuild: clean all
.PHONY: all clean rebuild
3. 安全特性
-
SSL/TLS加密
- 使用TLS 1.2/1.3协议
- 支持多种加密套件
- 证书验证
- 安全的密钥交换
-
证书管理
- 使用自签名证书
- 在生产环境中应使用CA签发的证书
-
多线程安全
- 使用互斥锁保护共享资源
- 线程安全的资源管理
4. 编译和运行
4.1 环境要求
- Ubuntu系统
- OpenSSL开发库
- g++编译器
4.2 安装依赖
sudo apt-get update
sudo apt-get install libssl-dev g++
4.3 生成证书
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes -subj "/CN=localhost"
4.4 编译程序
cd 03.加密通信系统
make
4.5 运行程序
- 启动服务器:
./ssl_server 8888
- 启动客户端:
./ssl_client localhost 8888
5. Makefile说明
5.1 主要配置
# 编译器设置
CXX = g++
CXXFLAGS = -std=c++17 -Wall -Wextra
# OpenSSL库
OPENSSL_LIBS = -lssl -lcrypto -lpthread
5.2 常用命令
make: 编译所有目标make clean: 清理编译产生的文件make rebuild: 清理后重新编译
6. 使用示例
- 服务器端输出:
Server started on port 8888
New client connected from 127.0.0.1
SSL connection established
Received: Hello, Server!
- 客户端输出:
Connected to server with TLS_AES_256_GCM_SHA384 encryption
Enter message (or 'quit' to exit): Hello, Server!
Server response: Server received: Hello, Server!
7. 扩展建议
-
功能扩展
- 添加用户认证
- 实现文件传输
- 添加数据压缩
- 实现心跳检测
- 添加日志系统
-
安全增强
- 使用CA签发的证书
- 实现证书吊销检查
- 添加双向认证
- 实现会话恢复
-
性能优化
- 使用线程池
- 实现连接池
- 添加数据缓存
- 优化内存使用
8. 注意事项
-
安全考虑
- 生产环境必须使用CA签发的证书
- 定期更新证书
- 注意保护私钥安全
- 实现适当的访问控制
-
性能考虑
- 合理设置线程数
- 注意内存使用
- 实现超时机制
- 处理异常情况
-
维护建议
- 定期检查日志
- 监控系统资源
- 及时更新依赖
- 做好备份工作
声明
该文章为学习过程中的笔记,目的是防止自己忘记,并且可以随时随地查阅。其中大部分内容收集于互联网。
897

被折叠的 条评论
为什么被折叠?



