commit dbb413b49dcd8ebce8b68f44be469b57dd7049ca Author: huanglinhuan Date: Tue Oct 14 20:06:34 2025 +0800 first commit diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..7178209 --- /dev/null +++ b/Makefile @@ -0,0 +1,133 @@ +# 支持通过参数传入CC编译器,默认使用gcc +CC ?= gcc +CFLAGS = -Wall -Wextra -std=c99 -O2 +LDFLAGS = -lssl -lcrypto -lpthread + +# 目标文件 +SERVER_TARGET = tls_server +CLIENT_TARGET = tls_client +TEST_TARGET = test_long_message +SERVER_SOURCE = tls_server.c +CLIENT_SOURCE = tls_client.c +TEST_SOURCE = test_long_message.c + +# 默认目标 +all: $(SERVER_TARGET) $(CLIENT_TARGET) $(TEST_TARGET) + +# 编译服务器 +$(SERVER_TARGET): $(SERVER_SOURCE) + $(CC) $(CFLAGS) -o $(SERVER_TARGET) $(SERVER_SOURCE) $(LDFLAGS) + +# 编译客户端 +$(CLIENT_TARGET): $(CLIENT_SOURCE) + $(CC) $(CFLAGS) -o $(CLIENT_TARGET) $(CLIENT_SOURCE) $(LDFLAGS) + +# 编译测试程序 +$(TEST_TARGET): $(TEST_SOURCE) + $(CC) $(CFLAGS) -o $(TEST_TARGET) $(TEST_SOURCE) -lssl -lcrypto + +# 生成证书 +cert: + chmod +x generate_cert.sh + ./generate_cert.sh + +# 运行服务器(默认端口8443) +run: $(SERVER_TARGET) cert + ./$(SERVER_TARGET) + +# 运行服务器(指定端口) +run-port: $(SERVER_TARGET) cert + @echo "请输入端口号:" + @read port; ./$(SERVER_TARGET) -p $$port + +# 测试客户端 +test: $(CLIENT_TARGET) + @echo "测试客户端,发送消息 'Hello World'" + ./$(CLIENT_TARGET) -m "Hello World" + +# 测试循环客户端 +test-loop: $(CLIENT_TARGET) + @echo "测试循环客户端,发送5次消息,间隔2秒" + ./$(CLIENT_TARGET) -m "Loop Test" -c 5 -i 2 + +# 测试TLS 1.2 +test-tls12: $(CLIENT_TARGET) + @echo "测试TLS 1.2连接" + ./$(CLIENT_TARGET) -m "TLS 1.2 Test" -t 1.2 + +# 测试TLS 1.3 +test-tls13: $(CLIENT_TARGET) + @echo "测试TLS 1.3连接" + ./$(CLIENT_TARGET) -m "TLS 1.3 Test" -t 1.3 + +# 测试TLS版本对比 +test-tls-compare: $(CLIENT_TARGET) + @echo "测试TLS版本对比" + @echo "=== TLS 1.2 测试 ===" + ./$(CLIENT_TARGET) -m "TLS 1.2" -t 1.2 -c 2 -i 1 + @echo "" + @echo "=== TLS 1.3 测试 ===" + ./$(CLIENT_TARGET) -m "TLS 1.3" -t 1.3 -c 2 -i 1 + @echo "" + @echo "=== 自动协商测试 ===" + ./$(CLIENT_TARGET) -m "Auto TLS" -t auto -c 2 -i 1 + +# 测试并发连接 +test-concurrent: $(CLIENT_TARGET) + @echo "测试并发客户端连接" + @echo "启动2个并发客户端..." + ./$(CLIENT_TARGET) -m "Concurrent 1" -c 1 & + ./$(CLIENT_TARGET) -m "Concurrent 2" -c 1 & + wait + @echo "并发测试完成" + +# 测试长消息 +test-long: $(TEST_TARGET) + @echo "测试长消息,发送1000字符消息" + ./$(TEST_TARGET) 1000 + +# 清理 +clean: + rm -f $(SERVER_TARGET) $(CLIENT_TARGET) $(TEST_TARGET) + rm -rf cert/ + +# 安装依赖(Ubuntu/Debian) +install-deps: + sudo apt-get update + sudo apt-get install -y libssl-dev + +# 安装依赖(CentOS/RHEL) +install-deps-centos: + sudo yum install -y openssl-devel + +# 显示编译器信息 +info: + @echo "当前编译器: $(CC)" + @echo "编译选项: $(CFLAGS)" + @echo "链接选项: $(LDFLAGS)" + +# 帮助信息 +help: + @echo "可用目标:" + @echo " all - 编译服务器、客户端和测试程序" + @echo " cert - 生成自签名证书" + @echo " run - 运行服务器(端口8443)" + @echo " run-port - 运行服务器(指定端口)" + @echo " test - 测试客户端连接" + @echo " test-loop - 测试循环客户端连接" + @echo " test-tls12 - 测试TLS 1.2连接" + @echo " test-tls13 - 测试TLS 1.3连接" + @echo " test-tls-compare - 测试TLS版本对比" + @echo " test-concurrent - 测试并发客户端连接" + @echo " test-long - 测试长消息发送" + @echo " clean - 清理生成的文件" + @echo " install-deps - 安装依赖(Ubuntu/Debian)" + @echo " info - 显示编译器信息" + @echo " help - 显示此帮助信息" + @echo "" + @echo "编译器参数:" + @echo " CC=clang make all - 使用clang编译器" + @echo " CC=gcc make all - 使用gcc编译器(默认)" + @echo " CC=cc make all - 使用系统默认编译器" + +.PHONY: all cert run run-port clean install-deps install-deps-centos info help diff --git a/README.md b/README.md new file mode 100755 index 0000000..5ffeb40 --- /dev/null +++ b/README.md @@ -0,0 +1,310 @@ +# TLS多客户端服务器 + +这是一个支持多客户端连接的TLS服务器,使用C语言实现,支持TLS 1.2和1.3协议。 + +## 功能特性 + +- ✅ 支持多客户端并发连接(最多100个) +- ✅ 支持TLS 1.2和1.3协议 +- ✅ 动态端口指定 +- ✅ 接收客户端消息并计算MD5返回 +- ✅ 线程安全的客户端处理 +- ✅ 优雅的服务器关闭 + +## 系统要求 + +- Linux/Unix系统 +- GCC编译器 +- OpenSSL开发库 +- pthread库 + +## 安装依赖 + +### Ubuntu/Debian系统 +```bash +make install-deps +``` + +### CentOS/RHEL系统 +```bash +make install-deps-centos +``` + +## 编译和运行 + +### 1. 编译项目 +```bash +# 使用默认gcc编译器 +make all + +# 使用指定编译器 +CC=clang make all # 使用clang编译器 +CC=gcc make all # 使用gcc编译器(默认) +CC=cc make all # 使用系统默认编译器 + +# 查看编译器信息 +make info +``` + +### 2. 生成自签名证书 +```bash +make cert +``` + +**注意**: 证书将生成在 `cert/` 目录中: +- `cert/server.key` - 服务器私钥 +- `cert/server.crt` - 服务器证书 + +### 3. 运行服务器 + +#### 使用默认端口8443 +```bash +make run +``` + +#### 指定端口运行 +```bash +make run-port +# 然后输入端口号,例如:9000 +``` + +#### 直接运行 +```bash +./tls_server -p 9000 # 指定端口9000 +./tls_server # 使用默认端口8443 +./tls_server -h # 显示帮助信息 +``` + +### 4. 测试客户端连接 +```bash +make test +``` + +#### 手动测试客户端 +```bash +./tls_client -m "Hello World" # 基本测试 +./tls_client -s 1500 # 发送1500字节01数据 +./tls_client -m "Hello" -c 5 -i 2 # 循环测试5次,间隔2秒 +./tls_client -s 2048 -c 3 -i 1 # 发送2048字节01数据,循环3次 +./tls_client -m "Test" -h 192.168.1.100 -p 9000 # 连接到指定服务器 +./tls_client -m "TLS1.2" -t 1.2 # 强制使用TLS 1.2 +./tls_client -s 512 -t 1.2 -c 2 -i 1 # 字节数+TLS版本测试 +./tls_client -m "TLS1.3" -t 1.3 # 强制使用TLS 1.3 +./tls_client -m "Auto" -t auto # 自动协商TLS版本 +./tls_client -m "Compare" -C -c 5 # TLS版本对比测试,循环5轮 +./tls_client -s 1024 -C -c 10 # TLS版本对比测试,1024字节,10轮 +``` + +## 使用说明 + +### 服务器端 +1. 启动服务器后,它会监听指定端口的TLS连接 +2. 支持最多100个并发客户端连接 +3. 每个客户端连接都会在独立线程中处理 +4. 服务器会显示连接状态和TLS版本信息 +5. 按Ctrl+C可以优雅地关闭服务器 +6. **新增功能**: 带时间戳的详细日志记录 +7. **新增功能**: 按IP地址统计连接成功率和耗时 + +### 命令行参数 +```bash +./tls_server -p 9000 # 在端口9000运行 +./tls_server # 使用默认端口8443 +./tls_server -h # 显示帮助信息 +``` + +### 客户端 +1. 连接到TLS服务器 +2. 发送消息给服务器 +3. 接收服务器计算的MD5哈希值 +4. 自动断开连接 +5. 支持循环测试,可指定测试次数和间隔 +6. 提供详细的测试统计报告 + +### 客户端参数 +```bash +./tls_client -m <消息> 或 -s <字节数> [-h 主机] [-p 端口] [-c 次数] [-i 间隔秒数] [-t TLS版本] [-C] +``` + +**参数说明:** +- `-m 消息`: 要发送的消息内容 +- `-s 字节数`: 要发送的字节数(发送01数据,最大4095字节) +- `-h 主机`: 服务器主机地址(默认: localhost) +- `-p 端口`: 服务器端口(默认: 8443) +- `-c 次数`: 循环测试次数(默认: 1) +- `-i 间隔`: 测试间隔秒数(默认: 1) +- `-t 版本`: TLS版本: 1.2, 1.3, auto(默认: auto) +- `-C`: TLS版本对比模式,每轮先测试TLS 1.2,等待2秒后测试TLS 1.3 + +### 测试统计报告 +客户端测试完成后会输出详细的统计信息: + +``` +======================================== + 测试统计报告 +======================================== +测试开始时间: Mon Jan 15 10:30:00 2024 +测试结束时间: Mon Jan 15 10:30:15 2024 +总耗时: 15.00 秒 +---------------------------------------- +总测试次数: 5 +成功次数: 5 +失败次数: 0 +成功率: 100.00% +---------------------------------------- +平均每次测试耗时: 3.00 秒 +======================================== +✅ 所有测试通过! +``` + +**统计信息包括:** +- 测试开始和结束时间 +- 总耗时 +- 总测试次数 +- 成功和失败次数 +- 成功率 +- 平均每次测试耗时 +- 失败率(如果有失败) + +## 项目结构 + +``` +. +├── tls_server.c # 服务器主程序 +├── tls_client.c # 客户端测试程序 +├── generate_cert.sh # 证书生成脚本 +├── Makefile # 编译配置 +├── cert/ # 证书目录 +│ ├── server.key # 服务器私钥 +│ └── server.crt # 服务器证书 +└── README.md # 项目说明 +``` + +## 技术实现 + +### 服务器端特性 +- 使用OpenSSL库实现TLS支持 +- 多线程处理客户端连接 +- 线程安全的客户端管理 +- 支持TLS 1.2和1.3协议 +- MD5哈希计算和返回 + +### 安全特性 +- TLS加密传输 +- 自签名证书(测试用) +- 客户端证书验证(可配置) + +## 示例输出 + +### 服务器端 +``` +[2024-01-15 10:30:00] 启动TLS服务器,端口: 8443 +[2024-01-15 10:30:00] 服务器已启动,等待客户端连接... +[2024-01-15 10:30:00] 支持TLS 1.2和1.3 +[2024-01-15 10:30:00] 按Ctrl+C停止服务器 +[2024-01-15 10:30:05] 新连接来自: 127.0.0.1:12345 +[2024-01-15 10:30:05] 当前活跃连接数: 0/100 +[2024-01-15 10:30:05] SSL握手成功,IP: 127.0.0.1,TLS版本: TLSv1.3 +[2024-01-15 10:30:05] 客户端处理线程已创建,当前连接数: 1 +[2024-01-15 10:30:05] 新客户端连接,IP: 127.0.0.1,线程ID: 140123456789,套接字: 4 +[2024-01-15 10:30:05] 收到客户端消息,IP: 127.0.0.1,长度: 11,内容: Hello World +[2024-01-15 10:30:05] MD5计算完成,IP: 127.0.0.1,结果: b10a8db164e0754105b7a99be72e3fe5 +[2024-01-15 10:30:05] 已发送MD5结果给客户端,IP: 127.0.0.1 +[2024-01-15 10:30:05] 开始清理客户端连接,IP: 127.0.0.1,套接字: 4 +[2024-01-15 10:30:05] 客户端连接已关闭,IP: 127.0.0.1,当前连接数: 0 +``` + +### IP统计报告示例 +``` +[2024-01-15 10:35:00] IP统计 [127.0.0.1]: 总次数=10, 成功次数=10, 成功率=100.00%, 耗时=300秒 +[2024-01-15 10:40:00] IP统计 [192.168.1.100]: 总次数=10, 成功次数=8, 成功率=80.00%, 耗时=600秒 +``` + +### 客户端 +``` +[2024-01-15 10:30:00] 连接到TLS服务器: localhost:8443 +[2024-01-15 10:30:00] 发送消息: Hello World +[2024-01-15 10:30:00] 测试次数: 1, 间隔: 1秒 +[2024-01-15 10:30:00] TLS版本: 自动协商 +[2024-01-15 10:30:00] 测试开始时间: Mon Jan 15 10:30:00 2024 + +[2024-01-15 10:30:00] === 测试 1/1 === +[2024-01-15 10:30:00] TCP连接成功 +[2024-01-15 10:30:00] SSL握手成功,TLS版本: TLSv1.3 +[2024-01-15 10:30:00] 消息已发送 (长度: 11) +[2024-01-15 10:30:00] 收到MD5结果: b10a8db164e0754105b7a99be72e3fe5 +[2024-01-15 10:30:00] 连接已关闭 + +[2024-01-15 10:30:01] ======================================== +[2024-01-15 10:30:01] 测试统计报告 +[2024-01-15 10:30:01] ======================================== +[2024-01-15 10:30:01] 测试开始时间: Mon Jan 15 10:30:00 2024 +[2024-01-15 10:30:01] 测试结束时间: Mon Jan 15 10:30:01 2024 +[2024-01-15 10:30:01] 总耗时: 1.00 秒 +[2024-01-15 10:30:01] ---------------------------------------- +[2024-01-15 10:30:01] 总测试次数: 1 +[2024-01-15 10:30:01] 成功次数: 1 +[2024-01-15 10:30:01] 失败次数: 0 +[2024-01-15 10:30:01] 总重试次数: 0 +[2024-01-15 10:30:01] 成功率: 100.00% +[2024-01-15 10:30:01] ---------------------------------------- +[2024-01-15 10:30:01] 平均每次测试耗时: 1.00 秒 +[2024-01-15 10:30:01] ======================================== +[2024-01-15 10:30:01] ✅ 所有测试通过! +``` + +## 故障排除 + +### 编译错误 +- 确保已安装OpenSSL开发库 +- 检查GCC版本是否支持C99标准 +- **struct timeval错误**: 已添加`#include `头文件 +- **pthread错误**: 确保链接pthread库 (`-lpthread`) + +### 编译器支持 +- **默认编译器**: gcc +- **支持编译器**: gcc, clang, cc +- **编译器参数**: 使用`CC=编译器名 make all`指定编译器 +- **编译器信息**: 使用`make info`查看当前编译器设置 + +### 连接错误 +- 确保端口未被占用 +- 检查防火墙设置 +- 验证证书文件是否存在 + +### SSL错误处理 +- **SSL读取错误: 1**: 通常是客户端关闭连接导致,已改进错误处理 +- **消息截断警告**: 当消息长度接近4KB时会显示警告 +- **客户端立即关闭**: 客户端现在会等待服务器响应后再关闭连接 +- **SSL系统调用错误**: 改进了SSL_ERROR_SYSCALL错误处理,防止服务器异常退出 +- **连接清理**: 所有SSL错误都会正确清理连接资源 + +### 多客户端连接问题 +- **服务器卡住**: 已添加线程分离和超时机制 +- **连接数统计**: 服务器会显示当前活跃连接数 +- **资源清理**: 改进了客户端连接清理逻辑 +- **线程管理**: 使用pthread_detach自动回收线程资源 + +### 日志功能 +- **时间戳日志**: 所有日志都带有精确的时间戳 +- **IP统计**: 按IP地址统计连接成功率和耗时 +- **统计报告**: 每10次连接自动生成统计报告 +- **详细记录**: 记录连接、SSL握手、消息处理等全过程 + +### 客户端日志功能 +- **时间戳日志**: 客户端所有操作都带有时间戳 +- **测试统计**: 显示测试次数、成功/失败次数、成功率 +- **性能监控**: 记录每次测试的耗时和平均耗时 +- **详细记录**: 记录连接建立、SSL握手、消息发送/接收等全过程 +- **重试机制**: 连接失败时自动重试3次,使用指数退避策略(2秒、4秒、8秒) +- **重试统计**: 统计总重试次数,重试成功不计入失败 +- **超时保护**: 套接字读写操作30秒超时,防止客户端卡住 + +### 性能优化 +- 调整MAX_CLIENTS常量以支持更多连接 +- 修改BUFFER_SIZE以适应更大的消息 +- 考虑使用连接池优化资源使用 + +## 许可证 + +本项目仅用于学习和测试目的。 diff --git a/cert/ca.crt b/cert/ca.crt new file mode 100755 index 0000000..f88620e --- /dev/null +++ b/cert/ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDozCCAougAwIBAgIUPJ2ri4qd4BpnUcb/6vCZ//2uYd8wDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCQ04xEDAOBgNVBAgMB0JlaWppbmcxEDAOBgNVBAcMB0Jl +aWppbmcxDjAMBgNVBAoMBU15T3JnMQswCQYDVQQLDAJJVDERMA8GA1UEAwwITXlS +b290Q0EwHhcNMjUxMDA3MDYwMDI3WhcNMzUxMDA1MDYwMDI3WjBhMQswCQYDVQQG +EwJDTjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzEOMAwGA1UE +CgwFTXlPcmcxCzAJBgNVBAsMAklUMREwDwYDVQQDDAhNeVJvb3RDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMf0LkX1LF71yhsnqM4laww8B6RRo3nF +UD8pzGr4J8iFhtPyUr8T4Q3B1Et98sV+7zx4qxgYaMZ1IMX6QDti/T1qurAONhy9 +/HDGDrvMYE0AOQhvRvcqicpayqNqjLBJgdzh92Uei5s8F30tqLVm8tN715UaVDuc +enjh6s9e1GpR6CzvbKLEmsUESC9YFeV1kdlbn+b5cFgDElBan2nEpS2sAUamc5pt ++h8cjwojd58o3s+Cfc69DXnbSzRVo/7DSLO0itBLNvoo1YBSmJkuGDzsu0dcUD3m +84scYvxzvOZiUqESEaqXRMPw7OcOAQSbjloUgWfiX35ntmdeK5xyk90CAwEAAaNT +MFEwHQYDVR0OBBYEFH2YOXkKFAfeuB+IXTTB5NjXFsBqMB8GA1UdIwQYMBaAFH2Y +OXkKFAfeuB+IXTTB5NjXFsBqMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAA7+FwMG6yJi9vDHdaFRWA/RFSTBCo5bcFJ7DO7DwvsEOfHnP5ygulDY +astft8RsGelVSlXJtWHaCdByST9V282q+P2Q2jjwfmVB5ATq2MAgobYsU3nwLg3r +c6zd34GeTJ6wjyGF5g3rDG8NqcHlARRwL8GbWX5lbcq9ooYLl9KHgFY+gz6u5njx +WyJdnCMLRUgTt5tsT/3k5PU2V9C5kwZh/eAocEsfhuXDplFHeqdvZTZaXD/oX+So +jPnLL6fsAoCskIhVVM0xGAXtWmhk+1LVtrqCfTQrqBhtXi5qCl3NLmBf+d0OClwh +HgkcqJYr+WaiEHLUyIdfZji/ZEml7aA= +-----END CERTIFICATE----- diff --git a/cert/ca.key b/cert/ca.key new file mode 100755 index 0000000..57b528a --- /dev/null +++ b/cert/ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDH9C5F9Sxe9cob +J6jOJWsMPAekUaN5xVA/Kcxq+CfIhYbT8lK/E+ENwdRLffLFfu88eKsYGGjGdSDF ++kA7Yv09arqwDjYcvfxwxg67zGBNADkIb0b3KonKWsqjaoywSYHc4fdlHoubPBd9 +Lai1ZvLTe9eVGlQ7nHp44erPXtRqUegs72yixJrFBEgvWBXldZHZW5/m+XBYAxJQ +Wp9pxKUtrAFGpnOabfofHI8KI3efKN7Pgn3OvQ1520s0VaP+w0iztIrQSzb6KNWA +UpiZLhg87LtHXFA95vOLHGL8c7zmYlKhEhGql0TD8OznDgEEm45aFIFn4l9+Z7Zn +XiuccpPdAgMBAAECggEAIXon7y2LxsBXHLHIqO8J26wHSYMjoCUheNnKMFSo8IEu +oDivku9EnFWJ8jO9nERS0KiRWMDpdeSxXoQ2EdtSc+B1LjnK5IgIhmcam2Wt7+Zs +JhXfZ013cWo/CBo0QOWluPIaRhNVo2Ftu1cUKn74g+D1qLCWTr61oJyOgDar0Lrn +Cf6DvZl5pGJVV3lQUiYNjZR5qEywpaMvVcVjRUaUElNplld9VLm9xE8lhwjq0GER +LQKt63p6b34kUKM8dS4cWr7+EutQPEwMLPtM/0HBUpid0qRIj5iZtROo86g8ksS1 +vzGQJ5asfgiRdZX7tkrj31RDg4latXQ8saHfZeOLzwKBgQDu0jI25NKHpxbWOveS +OBtZK12aiO4n/nria3YsOTGCWYqtFUsZqcfj7/C30KH0vKODNoy9933+5roEdOvc +FIo6PDUADiZNGN3Oy69EhBVuGr4OkK2LjjCSSI2jvWONTDN4lQ17nAiiJ0LMT/TX +CBIef0i/QpAOYeuUh8FT1Ph8DwKBgQDWVkIfGLXFGeRORjUBuVv0ceQMR1K8Nz0/ +ldR0nuwoxMReSgoP2OVlSXqiLWAC6zPuXxE8KBo7GkvxEc4+AcwcgPZoAkK0KGBO +BCyS6V45abp56nanAxgGZJ/BNd3MEma9rbraFjC/yF29heGeE0s+gR6uPMW32qJe +U8nBJFj1UwKBgCvxm3HEWwTA9w/GW+WY01duBlQ4G/JZ/gyJj34FrBl7FmxQvbfk +KLbFYLrB9fsNdtze/bi6wIFVvSayyO9/DAw5JdtzvxJyn+W8TuzBjRvsacpOTtCe +Akv4c6+MWrQWMGZgrtFu3ZvQs5bao4epoYPhEea3fcBXvjxfWnBtgKd7AoGAeTT8 +XWN230heEFmpfhkZRCnnwX3P7rn6O+v54h1BBWkIdx29hOquBtI/tFiek+f4TROb +xn4TH1smmOPt0qjniTLwpS6qFAFFPLklj8rCywrcNjd988JPIsZihTt1+wJo8Vi+ +crfbx4iCYjvEs8TLZ0RTWkrpsKfF7DvLuxpX6BsCgYBygdo3EGCuKlymw1V8xrWU +rumFLCqtTxUfTu4hzWpPM6wDBh6BNMOeXw8Z7bE69Ha8rWxGpu0qEgRM2RegNJza +f2j+hZUZbdJsGoClpq3ROBwBJHZ3ZUs+4po3JWQWc0DblaMOZftVIAh7EbMhmVPe +OwMin2eLv4aEzSEtSYK8aQ== +-----END PRIVATE KEY----- diff --git a/cert/client.crt b/cert/client.crt new file mode 100755 index 0000000..f0341d6 --- /dev/null +++ b/cert/client.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDTDCCAjQCFDcqUklN76USvOskALvfIUttDamKMA0GCSqGSIb3DQEBCwUAMGEx +CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW5n +MQ4wDAYDVQQKDAVNeU9yZzELMAkGA1UECwwCSVQxETAPBgNVBAMMCE15Um9vdENB +MB4XDTI1MTAwNzA2MDE1NFoXDTI2MTAwNzA2MDE1NFowZDELMAkGA1UEBhMCQ04x +EDAOBgNVBAgMB0JlaWppbmcxEDAOBgNVBAcMB0JlaWppbmcxDjAMBgNVBAoMBU15 +T3JnMQ8wDQYDVQQLDAZDbGllbnQxEDAOBgNVBAMMB2NsaWVudDEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaJLDgelGrpFYgFKqGUAvopUg709OHZjwT +FyEiBic7NgWWLSne5MFBMVY18nZF9khaJZn6wN//miubkb6hbP7695GERB/wVDTj +nMd9FjDaZvYoZQkxemjCBDpyYd5vfP7f83EkNEnD2VljBbRATfl7tXxcbELDHC9N +ukkFD/3sD8IiSpZyyO1U3Ljv/vuV4UCTadJlKB+R5hNqI7QWOr59bRQD2mykXGtx ++gf44rBXqfglhY2xevuvBHYvRncHARIjOvRUmf0ue3CHPtS6wafWiPoYz6Q92xa4 +xBDOtY9lrOZuwGzAsA0dRN80Uu2YmRUoe5bAnZiMk3iDBlt6dNafAgMBAAEwDQYJ +KoZIhvcNAQELBQADggEBAHV2eD8V79IF/u74mXjQxEalAJ0nA/ooMASbDIx08/wy +S4mwZl08yMFRHwV4nMp6kbRh81cWYtTe8+LW8w1mHUKd/7MzStKT93IADPULFjCi +4ee0wJmQePnWDxOcUUz6zEfh72W2Fy1CrZ99R0ZMF5ifUGUPNfmj0NsfqGgEReOO +ai3yNTEg0zg35+2SnHzodFerKWDeis5gP5EOURfHcKYKE3oEatxwn9//gb/sICoR +99rxHTO4BZB06DIArdxomZ84eanBkHGsJGuPjncR9fyLQcbP1SP0WUcR2p73xAd3 +EMBByvrT1m68g7L0SVqN05EshJoYWONb4gTHd2BCO0A= +-----END CERTIFICATE----- diff --git a/cert/client.key b/cert/client.key new file mode 100755 index 0000000..a72b547 --- /dev/null +++ b/cert/client.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCaJLDgelGrpFYg +FKqGUAvopUg709OHZjwTFyEiBic7NgWWLSne5MFBMVY18nZF9khaJZn6wN//miub +kb6hbP7695GERB/wVDTjnMd9FjDaZvYoZQkxemjCBDpyYd5vfP7f83EkNEnD2Vlj +BbRATfl7tXxcbELDHC9NukkFD/3sD8IiSpZyyO1U3Ljv/vuV4UCTadJlKB+R5hNq +I7QWOr59bRQD2mykXGtx+gf44rBXqfglhY2xevuvBHYvRncHARIjOvRUmf0ue3CH +PtS6wafWiPoYz6Q92xa4xBDOtY9lrOZuwGzAsA0dRN80Uu2YmRUoe5bAnZiMk3iD +Blt6dNafAgMBAAECggEAHzak1qAOX7qEcjSdH1ugPbkSeoL3h6iNK7R4UiJ62UOk +N/fnTap289OgyIXTq3Emz5JjruJVubWndPY7awbeT0XIoscEzK7QkvLRdqQCuoc0 ++5MSHIHUKs2eZEErQNpH5mOumo04Dr+5mRKzoH3pskJa74BAuK/BaHT7ilnlqmJp +xoVDilQC5jiGys4MpCtx2Kt8l2CAlsE84vZff+PGV4O0kDsqqky6uhuJtrTaZs7j +bFJoWcG9L9s/WZtwb32X11epHOmQv6mrzgFyminzkBoCmO7cBNB44eyQJnnNYece +MnFdklKCPuSYc0lgWSepuUkrz8hLKC8+QzQO668UsQKBgQDYfmM9ES087q+H9ooc +l/GZsEdV/iN+Kcm1JkyyypzRQrmVUTyAp9SFRaLiQP3ea6Jy/CUeCC1SWwPLJM9E +EA0jlCYIPFOhsT7I1EM5Qa7DWf1z8bAVUMs1cqZrzOegIbEiKSu+Ym4MMVtvKvON +OqaTtwwNUvyxVHmsuZBUZzzXOQKBgQC2RZLvI4p/Qzbpznsmq4beCSFEACRJTa/F +e58/Xbmfdwo42WU17548k7sN/Jgyg7PVu4+bY5ZAYMibXFtEHW+sBz/4Gf90BZxE +egiKD7gtEw4kxu8BfygJgWyszK4guzTYKx+DJRl2xtvGCNX10SrV1rEfHvYNHXj8 +BekIht0ElwKBgQCb/FSch2fE42Vt3WEdwQy+45hCiV4hZRKEhxf0KrBaxmzY/TNO +r54ceFQoGRPR0lO17Z8AyHt/Pzy4fckpDTeqTvAoNu87LW5DXU0iUAUPlCNeCuII +ObJwzC7EtVqesifiqS9veZQ5DMcIjjX1qDClddolL4oKawdQQFORvODFYQKBgB/l +FM0b3wRd8qH/K7WclkEMP/HyRGc/XN6lvzwLXov0/KjuAbPqdjoLb9QGu2s7eKCR +7ZM3Xfdt+CyXgLDupbfonN0BT54xzSJ+aDgggA4DI5pz5SbR5WOkbivetSmtGJYr +FZyRRV9vdM22hho5u9EnfF8Bv/STj7QqJJkFYG+JAoGBAKx9evvrTS1tgcduIZXm +fFQJ/Y4r2AtUqPs5TE69wdQg+WL35Njd0r3gguK4isur4NV3Yb97JUN95L9E2cY2 +asRkLNGiWwgFtSp6xTA6ltfLbdW+smZgeFkMTu8O6WBUiep6TEkRiR60UnKxDfwO +eNr+BzEVtLNmY43pf3uRjnfm +-----END PRIVATE KEY----- diff --git a/cert/server.crt b/cert/server.crt new file mode 100755 index 0000000..d39d0e0 --- /dev/null +++ b/cert/server.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUTCCAjkCFFDhJROu/swj7dMd1fokMaMYKNtfMA0GCSqGSIb3DQEBCwUAMGEx +CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW5n +MQ4wDAYDVQQKDAVNeU9yZzELMAkGA1UECwwCSVQxETAPBgNVBAMMCE15Um9vdENB +MB4XDTI1MTAwNzA2MDExN1oXDTI2MTAwNzA2MDExN1owaTELMAkGA1UEBhMCQ04x +EDAOBgNVBAgMB0JlaWppbmcxEDAOBgNVBAcMB0JlaWppbmcxDjAMBgNVBAoMBU15 +T3JnMQ8wDQYDVQQLDAZTZXJ2ZXIxFTATBgNVBAMMDG15c2VydmVyLmNvbTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPqMRUu5Vni7eAPEcstj2bfPOJXN +XtEvCLHH5XeVlmdUhwXZ9AlCITdjp2teV/hn6kbJACegY1g9IetnLqkWWm2MBvqm +OG9H2UfobSyfNiYmgI4X05KLlIzQ2vm2F0+sl5BQUv1t3ly4zXdb1q6O6xdiUaNG +d66DTL2MyaxCR8tgmhHiohEvozRzLUu63nbufva4CLALF71G45fq+jy+moIYeWop +SQn3Teu3HRTaV+XCMxCFw4TrJvN4aGDDHiE8f8TneSIISf8zEt4qGVzwSkOWTqZC +jkqe1vmV3qpMnfXdpsUYRXegKQjorIddWGBM86MisY3kFO9wmQjCggV0BssCAwEA +ATANBgkqhkiG9w0BAQsFAAOCAQEAKNIOPNNcZudVUq7ql16nnbBZrEkSF5WlMXZa +Zaka/Ix7/fuGJ2EKcy8npcPLOMSzt7DX9EmcIBF5FGrwBvLdrbR/ikW62vTgUv9q +l+P/VegPT6FXlU5AD5ur0hAYCsMk4EbT9ZfmU3qXDc55qXTQUY/dlzTOaCRBBQdO +PVImAdU/Zv3hKhXgj/93wWKdPFc3tjLiY3tqbMVJLkRaiQsR5tDVb8DQOXOgwWHf +PBdmrkLjYZHWk+wCinR50V9viS6KMXc/YJlDx1o5lfFdsMRWteDpHS4X01C7BF8R +vdJOr4sfVP8GRuFadW9GlEhRN4BKj/PecsZr+3HPUOHyfPesTw== +-----END CERTIFICATE----- diff --git a/cert/server.csr b/cert/server.csr new file mode 100755 index 0000000..a4696a4 --- /dev/null +++ b/cert/server.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICrjCCAZYCAQAwaTELMAkGA1UEBhMCQ04xEDAOBgNVBAgMB0JlaWppbmcxEDAO +BgNVBAcMB0JlaWppbmcxDjAMBgNVBAoMBU15T3JnMQ8wDQYDVQQLDAZTZXJ2ZXIx +FTATBgNVBAMMDG15c2VydmVyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAPqMRUu5Vni7eAPEcstj2bfPOJXNXtEvCLHH5XeVlmdUhwXZ9AlCITdj +p2teV/hn6kbJACegY1g9IetnLqkWWm2MBvqmOG9H2UfobSyfNiYmgI4X05KLlIzQ +2vm2F0+sl5BQUv1t3ly4zXdb1q6O6xdiUaNGd66DTL2MyaxCR8tgmhHiohEvozRz +LUu63nbufva4CLALF71G45fq+jy+moIYeWopSQn3Teu3HRTaV+XCMxCFw4TrJvN4 +aGDDHiE8f8TneSIISf8zEt4qGVzwSkOWTqZCjkqe1vmV3qpMnfXdpsUYRXegKQjo +rIddWGBM86MisY3kFO9wmQjCggV0BssCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IB +AQCWDmyzIhCsrDKrOb7MVN6GJHIqQdZj88zxil0KSR7wxHXCZD2TOJXUnwEnQgW7 +m/q4375rpYO5bjhDr0JxnIsS0LB/QDZKMNA6PgR1LcTUZsQValvDnEVu/u1rQOgR +IZoVrGcKjfJ7rYPnArAPqhyLEtME6QYz7hzBeRdZhN+P1HQdBT5tpXi84awZmr5P +6MgKUS4HWui11sO/TRAL9AR2721PNN+ZwycPuPOuZ6YusI/6x3Y4u0OxxNPeOBme +LXt/kbpU1WNj2MemEnMLDMDB6COF86tJFw/cUF+lW5kBlvWIFWwapCp22h0XtxfE +zOaJgcmGkn2egLvmF5S3c/Tq +-----END CERTIFICATE REQUEST----- diff --git a/cert/server.key b/cert/server.key new file mode 100755 index 0000000..54fc562 --- /dev/null +++ b/cert/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQD6jEVLuVZ4u3gD +xHLLY9m3zziVzV7RLwixx+V3lZZnVIcF2fQJQiE3Y6drXlf4Z+pGyQAnoGNYPSHr +Zy6pFlptjAb6pjhvR9lH6G0snzYmJoCOF9OSi5SM0Nr5thdPrJeQUFL9bd5cuM13 +W9aujusXYlGjRneug0y9jMmsQkfLYJoR4qIRL6M0cy1Lut527n72uAiwCxe9RuOX +6vo8vpqCGHlqKUkJ903rtx0U2lflwjMQhcOE6ybzeGhgwx4hPH/E53kiCEn/MxLe +Khlc8EpDlk6mQo5Kntb5ld6qTJ313abFGEV3oCkI6KyHXVhgTPOjIrGN5BTvcJkI +woIFdAbLAgMBAAECggEAZ97zc5tY0CDYdqdg+BVjU6LjUKed4ZdgQWQgK92mRxxy +BekAFT6HStFTvV2VlvRt2f7Gw6boyNI/V7qlS5Bq2POuiQeUaf4dhIRFjrRK3LIl +pcMXAbBAW8jSn6fwLiXdiATlAxAjmck71XoLnL6/lCg8tDYos/7XN9ZAXdv0q8mE +1+nnyS6WfWXBdOqDhgfvzwyIG/dfA9KmXfHw3dFXQL9up9M18d4dQLC7XtYxlL9h +ttUG5XvzkwnnKbrNVKKFy1bynl335NrujyAQjWTVU9GmWTZvd11DFWXm0raQ1Q/Y +zS+JQ+rtJwldthN2vyCC5Oj5xZSCldVkivLqfpk/8QKBgQD98EDLtr2DGC5GwEEm +g+Gne45XocCc683Xq/WpTR45kuSv5rzb9G6zbWRgF9Rn6dYnkFgwlU4WW6bF851V +UWGOGoE4DL4F2ecvc/Bnmwp5v1aoDCokS2QEBRDg+Y5I769L1PdQwWVRs85TQv9s +9DqAXAwjZAJJlKAqEiLABAkJLwKBgQD8lPieQytn43hWZfm+IA4zNLg4Fuhd9NPz +IsYCYFno4F2Ibp7kspm0HTf1u4/pXGCEbDIxgY4EX2KVQfTuEovx0VMlgGVJVsYZ +Z0LMmMkDe/xRh9Pta0uI5ApP+kxw/hv7ug+r4jrBdFxacM8913Q24xn1sGPbMxcw +t6bF7gK9JQKBgQCAtQISfpfFVz81SwJ6hAOegOhfkDNxFa9qLdVArz6vjb1tTnTQ +wy5MsRhcABf/ZyzNNsMMNNC0UlXQJS7MbIgWn2Z5QzQZAR3FFm12BcYkeQ9x82B0 +ruWNiAfLD5HHc/yUYefMPYmeBJWB7AZMceko3/6i/XCPXM5lJHYKfsEZrwKBgQC2 +zAGaWDZju2Zt8ONry7s7J95jCYEl7nguMG5pbd3kAezvPk/UZ8WBatwDBblDRE29 +yKgS2BY15+pq5w8h9V4+piWssF2dVCWOYQMhGznvQZ38S3b/DnXeHluwQg9sfxs1 +dRS+ar3nIBVuhtIViYZb6sPw4bWDAFi6M0+JU5W72QKBgQD02Z8VHXtdKbzWafK6 +TOJ3u5ReTL78yF4JLdtLLpnOJ0XFpKbLRzCYrBIuLwJgnTC1VqcnVezlCvcDj8fc +KUNQbEAFDMUedA9J4tIsohjZlbW1tbyAo7h160TOUg+15CIMLpI+6Or5ADXeyisv +T68iyFB+Qul1Nr/J/8JlPRD6pw== +-----END PRIVATE KEY----- diff --git a/tls_client.c b/tls_client.c new file mode 100755 index 0000000..1ac272e --- /dev/null +++ b/tls_client.c @@ -0,0 +1,566 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 4096 + +// 初始化OpenSSL +void init_openssl() { + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + SSL_library_init(); +} + +// 清理OpenSSL +void cleanup_openssl() { + EVP_cleanup(); + ERR_free_strings(); +} + +// 创建SSL上下文 +SSL_CTX *create_context(int tls_version) { + const SSL_METHOD *method; + SSL_CTX *ctx; + + method = TLS_client_method(); + ctx = SSL_CTX_new(method); + if (!ctx) { + perror("无法创建SSL上下文"); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + + // 设置TLS版本 + switch (tls_version) { + case 1: // TLS 1.2 + SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION); + break; + case 2: // TLS 1.3 + SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); + break; + case 0: // 自动协商(默认) + default: + // 不设置版本限制,让OpenSSL自动协商 + break; + } + + // 跳过证书验证(仅用于测试) + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + + return ctx; +} + +// 时间戳日志函数 +void log_with_timestamp(const char *format, ...) { + time_t now; + struct tm *tm_info; + char timestamp[64]; + va_list args; + + time(&now); + tm_info = localtime(&now); + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info); + + printf("[%s] ", timestamp); + va_start(args, format); + vprintf(format, args); + va_end(args); +} + +// 完整测试函数(包含重试逻辑) +int perform_test(struct sockaddr_in *server_addr, SSL_CTX *ssl_ctx, const char *message, + int byte_count, int max_retries, int *retry_count_out) { + int socket_fd; + SSL *ssl = NULL; + char buffer[BUFFER_SIZE]; + int bytes_received; + int current_retry = 0; + int test_success = 0; + + *retry_count_out = 0; + + log_with_timestamp("进入perform_test函数\n"); + + // 重试循环 + for (current_retry = 0; current_retry <= max_retries; current_retry++) { + log_with_timestamp("重试循环: 第 %d/%d 次尝试\n", current_retry, max_retries); + + if (current_retry > 0) { + // 指数退避:2^retry_count 秒,最大60秒 + int backoff_time = (1 << current_retry); // 2的幂:2, 4, 8, 16... + if (backoff_time > 60) { + backoff_time = 60; // 最大60秒 + } + log_with_timestamp("开始第 %d 次重试,等待%d秒(指数退避)...\n", current_retry, backoff_time); + sleep(backoff_time); + *retry_count_out = current_retry; + } + + // 创建套接字 + log_with_timestamp("开始创建套接字...\n"); + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd < 0) { + log_with_timestamp("创建套接字失败: %s\n", strerror(errno)); + continue; + } + log_with_timestamp("套接字创建成功,fd=%d\n", socket_fd); + + // 设置连接超时(30秒) + struct timeval connect_timeout; + connect_timeout.tv_sec = 30; + connect_timeout.tv_usec = 0; + + if (setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &connect_timeout, sizeof(connect_timeout)) < 0) { + log_with_timestamp("设置连接超时失败: %s\n", strerror(errno)); + } + + // 连接到服务器 + log_with_timestamp("开始连接到服务器...\n"); + if (connect(socket_fd, (struct sockaddr *)server_addr, sizeof(*server_addr)) < 0) { + log_with_timestamp("连接失败: %s\n", strerror(errno)); + close(socket_fd); + continue; + } + + log_with_timestamp("TCP连接成功\n"); + + // 设置套接字超时(30秒) + struct timeval timeout; + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { + log_with_timestamp("设置接收超时失败\n"); + } + + if (setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) { + log_with_timestamp("设置发送超时失败\n"); + } + + // 创建SSL连接 + ssl = SSL_new(ssl_ctx); + if (!ssl) { + log_with_timestamp("SSL对象创建失败\n"); + close(socket_fd); + continue; + } + + SSL_set_fd(ssl, socket_fd); + + if (SSL_connect(ssl) <= 0) { + log_with_timestamp("SSL握手失败\n"); + ERR_print_errors_fp(stderr); + SSL_free(ssl); + close(socket_fd); + continue; + } + + log_with_timestamp("SSL握手成功,TLS版本: %s\n", SSL_get_version(ssl)); + + // 发送消息 + int write_result = SSL_write(ssl, message, strlen(message)); + if (write_result <= 0) { + int ssl_error = SSL_get_error(ssl, write_result); + log_with_timestamp("发送消息失败,SSL错误: %d\n", ssl_error); + if (ssl_error == SSL_ERROR_SYSCALL) { + log_with_timestamp("系统调用错误: %s\n", strerror(errno)); + } + SSL_free(ssl); + close(socket_fd); + continue; + } + + if (byte_count > 0) { + log_with_timestamp("字节数据已发送 (长度: %zu)\n", strlen(message)); + } else { + log_with_timestamp("消息已发送 (长度: %zu)\n", strlen(message)); + } + + // 等待一小段时间,确保服务器处理完成 + usleep(100000); // 等待100ms + + // 接收MD5结果 + bytes_received = SSL_read(ssl, buffer, BUFFER_SIZE - 1); + if (bytes_received <= 0) { + int ssl_error = SSL_get_error(ssl, bytes_received); + log_with_timestamp("接收MD5结果失败,SSL错误: %d\n", ssl_error); + + // 详细的错误诊断 + switch (ssl_error) { + case SSL_ERROR_ZERO_RETURN: + log_with_timestamp("服务器关闭连接\n"); + break; + case SSL_ERROR_WANT_READ: + log_with_timestamp("SSL需要读取数据(可能超时)\n"); + break; + case SSL_ERROR_WANT_WRITE: + log_with_timestamp("SSL需要写入数据\n"); + break; + case SSL_ERROR_SYSCALL: + if (errno == EAGAIN || errno == EWOULDBLOCK) { + log_with_timestamp("接收超时(30秒无响应)\n"); + } else { + log_with_timestamp("系统调用错误: %s\n", strerror(errno)); + } + break; + case SSL_ERROR_SSL: + log_with_timestamp("SSL协议错误\n"); + ERR_print_errors_fp(stderr); + break; + default: + log_with_timestamp("未知SSL错误\n"); + break; + } + + SSL_free(ssl); + close(socket_fd); + continue; + } + + buffer[bytes_received] = '\0'; + log_with_timestamp("收到MD5结果: %s\n", buffer); + + // 清理连接 + SSL_shutdown(ssl); + SSL_free(ssl); + close(socket_fd); + + log_with_timestamp("连接已关闭\n"); + + test_success = 1; + break; + } + + return test_success; +} + +int main(int argc, char *argv[]) { + char *host = "localhost"; + int port = 8443; + int socket_fd; + struct sockaddr_in server_addr; + SSL_CTX *ssl_ctx; + char message[BUFFER_SIZE]; + int test_count = 1; // 默认测试1次 + int test_interval = 1; // 默认间隔1秒 + int tls_version = 0; // 默认自动协商TLS版本 + int byte_count = 0; // 字节数参数,0表示使用消息内容 + int tls_compare_mode = 0; // TLS版本对比测试模式,0=关闭,1=开启 + int c; + + // 统计变量 + int success_count = 0; // 成功次数 + int failure_count = 0; // 失败次数 + int total_retry_count = 0; // 总重试次数 + time_t start_time, end_time; // 开始和结束时间 + + // 解析命令行参数 + while ((c = getopt(argc, argv, "m:h:p:c:i:t:s:C")) != -1) { + switch (c) { + case 'm': + strcpy(message, optarg); + break; + case 'h': + host = optarg; + break; + case 'p': + port = atoi(optarg); + if (port <= 0 || port > 65535) { + printf("错误: 端口号必须在1-65535之间\n"); + exit(EXIT_FAILURE); + } + break; + case 'c': + test_count = atoi(optarg); + if (test_count <= 0) { + printf("错误: 测试次数必须大于0\n"); + exit(EXIT_FAILURE); + } + break; + case 'i': + test_interval = atoi(optarg); + if (test_interval < 0) { + printf("错误: 测试间隔不能为负数\n"); + exit(EXIT_FAILURE); + } + break; + case 't': + if (strcmp(optarg, "1.2") == 0) { + tls_version = 1; // TLS 1.2 + } else if (strcmp(optarg, "1.3") == 0) { + tls_version = 2; // TLS 1.3 + } else if (strcmp(optarg, "auto") == 0) { + tls_version = 0; // 自动协商 + } else { + printf("错误: 无效的TLS版本 '%s',支持: 1.2, 1.3, auto\n", optarg); + exit(EXIT_FAILURE); + } + break; + case 's': + byte_count = atoi(optarg); + if (byte_count <= 0) { + printf("错误: 字节数必须大于0\n"); + exit(EXIT_FAILURE); + } + break; + case 'C': + tls_compare_mode = 1; + break; + case '?': + printf("使用 -h 查看帮助信息\n"); + exit(EXIT_FAILURE); + default: + abort(); + } + } + + // 如果没有通过-m参数指定消息,检查位置参数 + if (strlen(message) == 0 && optind < argc) { + strcpy(message, argv[optind]); + } + + // 检查必需参数:必须有消息内容或字节数 + if (strlen(message) == 0 && byte_count == 0) { + printf("用法: %s -m <消息> 或 -s <字节数> [-h 主机] [-p 端口] [-c 次数] [-i 间隔秒数] [-t TLS版本] [-C]\n", argv[0]); + printf("选项:\n"); + printf(" -m 消息 要发送的消息内容\n"); + printf(" -s 字节数 要发送的字节数(发送01数据)\n"); + printf(" -h 主机 服务器主机地址 (默认: localhost)\n"); + printf(" -p 端口 服务器端口 (默认: 8443)\n"); + printf(" -c 次数 循环测试次数 (默认: 1)\n"); + printf(" -i 间隔 测试间隔秒数 (默认: 1)\n"); + printf(" -t 版本 TLS版本: 1.2, 1.3, auto (默认: auto)\n"); + printf(" -C TLS版本对比模式:先测试TLS1.2,等待2秒后测试TLS1.3\n"); + printf("\n示例:\n"); + printf(" %s -m \"Hello\" -c 5 -i 2 # 发送Hello消息5次,间隔2秒\n", argv[0]); + printf(" %s -s 1024 # 发送1024字节的01数据\n", argv[0]); + printf(" %s -s 2048 -c 3 -i 1 # 发送2048字节01数据,循环3次\n", argv[0]); + printf(" %s -m \"Test\" -h 192.168.1.100 -p 9000 # 连接到指定服务器\n", argv[0]); + printf(" %s -m \"TLS1.2\" -t 1.2 # 强制使用TLS 1.2\n", argv[0]); + printf(" %s -m \"TLS1.3\" -t 1.3 # 强制使用TLS 1.3\n", argv[0]); + printf(" %s -m \"Compare\" -C -c 5 # TLS版本对比测试,循环5轮\n", argv[0]); + exit(EXIT_FAILURE); + } + + log_with_timestamp("连接到TLS服务器: %s:%d\n", host, port); + + // 根据参数类型显示不同的信息 + if (byte_count > 0) { + // 检查字节数是否超出缓冲区大小 + if (byte_count > BUFFER_SIZE - 1) { + printf("错误: 字节数 %d 超出最大缓冲区大小 %d\n", byte_count, BUFFER_SIZE - 1); + exit(EXIT_FAILURE); + } + + log_with_timestamp("发送字节数: %d (01数据)\n", byte_count); + // 生成01数据 + for (int i = 0; i < byte_count; i++) { + message[i] = '0' + (i % 2); // 交替发送0和1 + } + message[byte_count] = '\0'; + } else { + log_with_timestamp("发送消息: %s\n", message); + } + + log_with_timestamp("测试次数: %d, 间隔: %d秒\n", test_count, test_interval); + + // 显示TLS版本信息 + const char *tls_version_str; + switch (tls_version) { + case 1: + tls_version_str = "TLS 1.2"; + break; + case 2: + tls_version_str = "TLS 1.3"; + break; + case 0: + default: + tls_version_str = "自动协商"; + break; + } + // 显示测试模式 + if (tls_compare_mode) { + log_with_timestamp("TLS版本对比模式: 每轮先测试TLS 1.2,等待2秒后测试TLS 1.3\n"); + } else { + log_with_timestamp("TLS版本: %s\n", tls_version_str); + } + + // 记录开始时间 + time(&start_time); + log_with_timestamp("测试开始时间: %s", ctime(&start_time)); + + // 初始化OpenSSL + init_openssl(); + + // 执行循环测试 + for (int i = 1; i <= test_count; i++) { + if (tls_compare_mode) { + // TLS版本对比模式:先测试TLS 1.2,再测试TLS 1.3 + log_with_timestamp("\n=== 测试轮次 %d/%d ===\n", i, test_count); + + // 测试TLS 1.2 + log_with_timestamp("\n--- TLS 1.2 测试 ---\n"); + ssl_ctx = create_context(1); // 1 = TLS 1.2 + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + + if (inet_pton(AF_INET, host, &server_addr.sin_addr) <= 0) { + log_with_timestamp("地址解析失败: %s\n", strerror(errno)); + failure_count++; + } else { + int retry_count = 0; + if (perform_test(&server_addr, ssl_ctx, message, byte_count, 3, &retry_count)) { + log_with_timestamp("TLS 1.2 测试成功\n"); + success_count++; + total_retry_count += retry_count; + } else { + log_with_timestamp("TLS 1.2 测试失败(已重试 %d 次)\n", retry_count); + failure_count++; + total_retry_count += retry_count; + } + } + SSL_CTX_free(ssl_ctx); + + // 等待2秒 + log_with_timestamp("等待2秒后测试TLS 1.3...\n"); + sleep(1); + + // 测试TLS 1.3 + log_with_timestamp("\n--- TLS 1.3 测试 ---\n"); + ssl_ctx = create_context(2); // 2 = TLS 1.3 + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + + if (inet_pton(AF_INET, host, &server_addr.sin_addr) <= 0) { + log_with_timestamp("地址解析失败: %s\n", strerror(errno)); + failure_count++; + } else { + int retry_count = 0; + if (perform_test(&server_addr, ssl_ctx, message, byte_count, 3, &retry_count)) { + log_with_timestamp("TLS 1.3 测试成功\n"); + success_count++; + total_retry_count += retry_count; + } else { + log_with_timestamp("TLS 1.3 测试失败(已重试 %d 次)\n", retry_count); + failure_count++; + total_retry_count += retry_count; + } + } + SSL_CTX_free(ssl_ctx); + + log_with_timestamp("--- 本轮测试完成 ---\n"); + } else { + // 普通测试模式 + log_with_timestamp("\n=== 测试 %d/%d ===\n", i, test_count); + + // 创建SSL上下文(只创建一次) + if (i == 1) { + ssl_ctx = create_context(tls_version); + } + + // 设置服务器地址 + log_with_timestamp("开始设置服务器地址: %s:%d\n", host, port); + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + + log_with_timestamp("开始解析IP地址...\n"); + if (inet_pton(AF_INET, host, &server_addr.sin_addr) <= 0) { + log_with_timestamp("地址解析失败: %s\n", strerror(errno)); + failure_count++; + continue; + } + log_with_timestamp("地址解析成功\n"); + + // 执行测试(包含重试逻辑) + log_with_timestamp("开始执行测试...\n"); + int retry_count = 0; + if (perform_test(&server_addr, ssl_ctx, message, byte_count, 3, &retry_count)) { + log_with_timestamp("测试成功\n"); + success_count++; + total_retry_count += retry_count; + } else { + log_with_timestamp("测试失败(已重试 %d 次)\n", retry_count); + failure_count++; + total_retry_count += retry_count; + } + } + + // 如果不是最后一次测试,等待指定间隔 + if (i < test_count) { + log_with_timestamp("等待 %d 秒后进行下一次测试...\n", test_interval); + sleep(test_interval); + } + } + + // 清理SSL上下文(非对比模式) + if (!tls_compare_mode && ssl_ctx) { + SSL_CTX_free(ssl_ctx); + } + + // 记录结束时间 + time(&end_time); + + // 最终清理 + cleanup_openssl(); + + // 计算统计信息 + int total_tests = success_count + failure_count; + double success_rate = (total_tests > 0) ? ((double)success_count / total_tests) * 100.0 : 0.0; + double elapsed_time = difftime(end_time, start_time); + + // 输出统计信息 + log_with_timestamp("\n"); + log_with_timestamp("========================================\n"); + log_with_timestamp(" 测试统计报告\n"); + log_with_timestamp("========================================\n"); + log_with_timestamp("测试开始时间: %s", ctime(&start_time)); + log_with_timestamp("测试结束时间: %s", ctime(&end_time)); + log_with_timestamp("总耗时: %.2f 秒\n", elapsed_time); + log_with_timestamp("----------------------------------------\n"); + log_with_timestamp("总测试次数: %d\n", total_tests); + log_with_timestamp("成功次数: %d\n", success_count); + log_with_timestamp("失败次数: %d\n", failure_count); + log_with_timestamp("总重试次数: %d\n", total_retry_count); + log_with_timestamp("成功率: %.2f%%\n", success_rate); + log_with_timestamp("----------------------------------------\n"); + + if (success_count > 0) { + log_with_timestamp("平均每次测试耗时: %.2f 秒\n", elapsed_time / success_count); + } + + if (failure_count > 0) { + log_with_timestamp("失败率: %.2f%%\n", 100.0 - success_rate); + } + + log_with_timestamp("========================================\n"); + + // 根据成功率返回适当的退出码 + if (success_rate >= 100.0) { + log_with_timestamp("✅ 所有测试通过!\n"); + return 0; + } else if (success_rate >= 80.0) { + log_with_timestamp("⚠️ 大部分测试通过,有少量失败\n"); + return 1; + } else { + log_with_timestamp("❌ 测试失败率较高,请检查服务器状态\n"); + return 2; + } +} diff --git a/tls_server.c b/tls_server.c new file mode 100755 index 0000000..c2e47f5 --- /dev/null +++ b/tls_server.c @@ -0,0 +1,497 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CLIENTS 100 +#define BUFFER_SIZE 4096 +#define MAX_MESSAGE_SIZE 4096 +#define CLIENT_TIMEOUT 30 // 客户端超时时间(秒) + +// 全局变量 +SSL_CTX *ssl_ctx; +int server_socket; +int client_count = 0; +pthread_mutex_t client_mutex = PTHREAD_MUTEX_INITIALIZER; + +// IP统计结构体 +typedef struct { + char ip[INET_ADDRSTRLEN]; + int total_connections; + int successful_connections; + time_t first_connection_time; + time_t last_connection_time; +} ip_stats_t; + +ip_stats_t ip_statistics[MAX_CLIENTS]; +pthread_mutex_t ip_stats_mutex = PTHREAD_MUTEX_INITIALIZER; + +// 时间戳日志函数 +void log_with_timestamp(const char *format, ...) { + time_t now; + struct tm *tm_info; + char timestamp[64]; + va_list args; + + time(&now); + tm_info = localtime(&now); + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info); + + printf("[%s] ", timestamp); + va_start(args, format); + vprintf(format, args); + va_end(args); +} + +// 更新IP统计信息 +void update_ip_stats(const char *ip, int success) { + pthread_mutex_lock(&ip_stats_mutex); + + // 查找或创建IP统计记录 + int index = -1; + for (int i = 0; i < MAX_CLIENTS; i++) { + if (strlen(ip_statistics[i].ip) == 0) { + index = i; + strcpy(ip_statistics[i].ip, ip); + ip_statistics[i].total_connections = 0; + ip_statistics[i].successful_connections = 0; + ip_statistics[i].first_connection_time = time(NULL); + break; + } else if (strcmp(ip_statistics[i].ip, ip) == 0) { + index = i; + break; + } + } + + if (index >= 0) { + ip_statistics[index].total_connections++; + if (success) { + ip_statistics[index].successful_connections++; + } + ip_statistics[index].last_connection_time = time(NULL); + + // 每10次连接统计一次 + if (ip_statistics[index].total_connections % 10 == 0) { + double success_rate = (double)ip_statistics[index].successful_connections / + ip_statistics[index].total_connections * 100.0; + time_t duration = ip_statistics[index].last_connection_time - + ip_statistics[index].first_connection_time; + + log_with_timestamp("IP统计 [%s]: 总次数=%d, 成功次数=%d, 成功率=%.2f%%, 耗时=%ld秒\n", + ip, ip_statistics[index].total_connections, + ip_statistics[index].successful_connections, + success_rate, duration); + } + } + + pthread_mutex_unlock(&ip_stats_mutex); +} + +// 客户端结构体 +typedef struct { + int socket; + SSL *ssl; + pthread_t thread; + int active; +} client_t; + +client_t clients[MAX_CLIENTS]; + +// 初始化OpenSSL +void init_openssl() { + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + SSL_library_init(); +} + +// 清理OpenSSL +void cleanup_openssl() { + EVP_cleanup(); + ERR_free_strings(); +} + +// 创建SSL上下文 +SSL_CTX *create_context() { + const SSL_METHOD *method; + SSL_CTX *ctx; + + // 使用TLS方法,支持1.2和1.3 + method = TLS_server_method(); + ctx = SSL_CTX_new(method); + if (!ctx) { + perror("无法创建SSL上下文"); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + + // 设置最小TLS版本为1.2 + SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); + + // 加载证书和私钥(从cert目录加载) + if (SSL_CTX_use_certificate_file(ctx, "cert/server.crt", SSL_FILETYPE_PEM) <= 0) { + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + + if (SSL_CTX_use_PrivateKey_file(ctx, "cert/server.key", SSL_FILETYPE_PEM) <= 0) { + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + + return ctx; +} + +// 计算MD5哈希 +void calculate_md5(const char *input, char *output) { + unsigned char digest[MD5_DIGEST_LENGTH]; + MD5_CTX ctx; + + MD5_Init(&ctx); + MD5_Update(&ctx, input, strlen(input)); + MD5_Final(digest, &ctx); + + for (int i = 0; i < MD5_DIGEST_LENGTH; i++) { + sprintf(output + (i * 2), "%02x", digest[i]); + } + output[32] = '\0'; +} + +// 处理客户端连接 +void *handle_client(void *arg) { + client_t *client = (client_t *)arg; + char buffer[BUFFER_SIZE]; + char md5_result[33]; + int bytes_received; + char client_ip[INET_ADDRSTRLEN]; + int connection_success = 0; + + // 获取客户端IP地址 + struct sockaddr_in client_addr; + socklen_t addr_len = sizeof(client_addr); + if (getpeername(client->socket, (struct sockaddr*)&client_addr, &addr_len) == 0) { + inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN); + } else { + strcpy(client_ip, "unknown"); + } + + log_with_timestamp("新客户端连接,IP: %s,线程ID: %lu,套接字: %d\n", + client_ip, client->thread, client->socket); + + while (client->active) { + // 检查SSL连接状态 + if (SSL_get_shutdown(client->ssl) & SSL_RECEIVED_SHUTDOWN) { + printf("检测到SSL关闭信号\n"); + break; + } + + // 设置套接字超时 + struct timeval timeout; + timeout.tv_sec = 30; // 30秒超时 + timeout.tv_usec = 0; + setsockopt(client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + + // 检查连接是否仍然有效 + if (!client->active || client->socket < 0) { + log_with_timestamp("客户端连接已失效,退出处理,IP: %s\n", client_ip); + goto cleanup; + } + + // 接收客户端消息 + bytes_received = SSL_read(client->ssl, buffer, MAX_MESSAGE_SIZE); + + if (bytes_received <= 0) { + int ssl_error = SSL_get_error(client->ssl, bytes_received); + switch (ssl_error) { + case SSL_ERROR_ZERO_RETURN: + log_with_timestamp("客户端正常断开连接,IP: %s\n", client_ip); + goto cleanup; + case SSL_ERROR_WANT_READ: + printf("SSL需要更多数据,继续等待...\n"); + continue; + case SSL_ERROR_WANT_WRITE: + printf("SSL需要写入数据,继续等待...\n"); + continue; + case SSL_ERROR_SSL: + // 检查是否是客户端关闭连接导致的错误 + if (bytes_received == 0) { + log_with_timestamp("客户端关闭连接,IP: %s\n", client_ip); + } else { + log_with_timestamp("SSL协议错误,可能是数据格式问题或连接异常,IP: %s\n", client_ip); + ERR_print_errors_fp(stderr); + } + // 尝试清理SSL错误队列 + ERR_clear_error(); + goto cleanup; + case SSL_ERROR_SYSCALL: + if (bytes_received == 0) { + log_with_timestamp("客户端关闭连接(系统调用),IP: %s\n", client_ip); + } else { + log_with_timestamp("SSL系统调用错误,可能是网络问题,IP: %s\n", client_ip); + } + // 不要直接break,让连接正常清理 + goto cleanup; + default: + log_with_timestamp("SSL读取错误: %d,IP: %s\n", ssl_error, client_ip); + goto cleanup; + } + break; + } + + buffer[bytes_received] = '\0'; + + // 检查消息长度 + if (bytes_received >= MAX_MESSAGE_SIZE - 1) { + printf("警告: 消息可能被截断,长度: %d\n", bytes_received); + } + + log_with_timestamp("收到客户端消息,IP: %s,长度: %d,内容: %s\n", + client_ip, bytes_received, buffer); + + // 计算MD5 + calculate_md5(buffer, md5_result); + log_with_timestamp("MD5计算完成,IP: %s,结果: %s\n", client_ip, md5_result); + + // 发送MD5结果给客户端 + if (SSL_write(client->ssl, md5_result, strlen(md5_result)) <= 0) { + int write_error = SSL_get_error(client->ssl, -1); + log_with_timestamp("发送MD5结果失败,SSL错误: %d,IP: %s\n", write_error, client_ip); + goto cleanup; + } + + log_with_timestamp("已发送MD5结果给客户端,IP: %s\n", client_ip); + connection_success = 1; // 标记连接成功 + } + +cleanup: + // 更新IP统计 + update_ip_stats(client_ip, connection_success); + + // 清理客户端连接 + log_with_timestamp("开始清理客户端连接,IP: %s,套接字: %d\n", client_ip, client->socket); + + if (client->ssl) { + SSL_shutdown(client->ssl); + SSL_free(client->ssl); + client->ssl = NULL; + } + + if (client->socket >= 0) { + close(client->socket); + client->socket = -1; + } + + pthread_mutex_lock(&client_mutex); + client->active = 0; + client_count--; + pthread_mutex_unlock(&client_mutex); + + log_with_timestamp("客户端连接已关闭,IP: %s,当前连接数: %d\n", client_ip, client_count); + return NULL; +} + +// 信号处理函数 +void signal_handler(int sig) { + printf("\n收到信号 %d,正在关闭服务器...\n", sig); + + // 关闭所有客户端连接 + for (int i = 0; i < MAX_CLIENTS; i++) { + if (clients[i].active) { + clients[i].active = 0; + if (clients[i].ssl) { + SSL_shutdown(clients[i].ssl); + SSL_free(clients[i].ssl); + } + if (clients[i].socket > 0) { + close(clients[i].socket); + } + } + } + + if (server_socket > 0) { + close(server_socket); + } + + if (ssl_ctx) { + SSL_CTX_free(ssl_ctx); + } + + cleanup_openssl(); + exit(0); +} + +int main(int argc, char *argv[]) { + int port = 8443; // 默认端口 + struct sockaddr_in server_addr, client_addr; + socklen_t client_len = sizeof(client_addr); + int opt = 1; + int c; + + // 解析命令行参数 + while ((c = getopt(argc, argv, "p:h")) != -1) { + switch (c) { + case 'p': + port = atoi(optarg); + if (port <= 0 || port > 65535) { + printf("错误: 端口号必须在1-65535之间\n"); + exit(EXIT_FAILURE); + } + break; + case 'h': + printf("用法: %s [-p 端口] [-h]\n", argv[0]); + printf("选项:\n"); + printf(" -p 端口 指定服务器端口 (默认: 8443)\n"); + printf(" -h 显示此帮助信息\n"); + printf("\n示例:\n"); + printf(" %s -p 9000 # 在端口9000运行服务器\n", argv[0]); + printf(" %s # 在默认端口8443运行服务器\n", argv[0]); + exit(EXIT_SUCCESS); + case '?': + printf("使用 -h 查看帮助信息\n"); + exit(EXIT_FAILURE); + default: + abort(); + } + } + + log_with_timestamp("启动TLS服务器,端口: %d\n", port); + + // 设置信号处理 + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + // 初始化OpenSSL + init_openssl(); + + // 创建SSL上下文 + ssl_ctx = create_context(); + + // 创建服务器套接字 + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket < 0) { + perror("创建套接字失败"); + exit(EXIT_FAILURE); + } + + // 设置套接字选项 + if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + perror("设置套接字选项失败"); + exit(EXIT_FAILURE); + } + + // 绑定地址 + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(port); + + if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("绑定地址失败"); + exit(EXIT_FAILURE); + } + + // 开始监听 + if (listen(server_socket, 10) < 0) { + perror("监听失败"); + exit(EXIT_FAILURE); + } + + log_with_timestamp("服务器已启动,等待客户端连接...\n"); + log_with_timestamp("支持TLS 1.2和1.3\n"); + log_with_timestamp("按Ctrl+C停止服务器\n"); + + // 初始化客户端数组 + for (int i = 0; i < MAX_CLIENTS; i++) { + clients[i].socket = -1; + clients[i].ssl = NULL; + clients[i].active = 0; + } + + // 主循环:接受客户端连接 + while (1) { + int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len); + if (client_socket < 0) { + perror("接受连接失败"); + continue; + } + + log_with_timestamp("新连接来自: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + log_with_timestamp("当前活跃连接数: %d/%d\n", client_count, MAX_CLIENTS); + + // 检查是否达到最大客户端数 + if (client_count >= MAX_CLIENTS) { + log_with_timestamp("已达到最大客户端连接数,拒绝新连接\n"); + close(client_socket); + continue; + } + + // 创建SSL连接 + SSL *ssl = SSL_new(ssl_ctx); + SSL_set_fd(ssl, client_socket); + + if (SSL_accept(ssl) <= 0) { + log_with_timestamp("SSL握手失败,IP: %s\n", inet_ntoa(client_addr.sin_addr)); + ERR_print_errors_fp(stderr); + SSL_free(ssl); + close(client_socket); + continue; + } + + log_with_timestamp("SSL握手成功,IP: %s,TLS版本: %s\n", + inet_ntoa(client_addr.sin_addr), SSL_get_version(ssl)); + + // 查找空闲的客户端槽位 + int client_index = -1; + pthread_mutex_lock(&client_mutex); + for (int i = 0; i < MAX_CLIENTS; i++) { + if (!clients[i].active) { + client_index = i; + break; + } + } + + if (client_index == -1) { + log_with_timestamp("没有可用的客户端槽位\n"); + SSL_free(ssl); + close(client_socket); + pthread_mutex_unlock(&client_mutex); + continue; + } + + // 设置客户端信息 + clients[client_index].socket = client_socket; + clients[client_index].ssl = ssl; + clients[client_index].active = 1; + client_count++; + + // 创建处理线程 + if (pthread_create(&clients[client_index].thread, NULL, handle_client, &clients[client_index]) != 0) { + log_with_timestamp("创建线程失败\n"); + clients[client_index].active = 0; + client_count--; + SSL_free(ssl); + close(client_socket); + pthread_mutex_unlock(&client_mutex); + continue; + } else { + // 分离线程,让系统自动回收线程资源 + pthread_detach(clients[client_index].thread); + log_with_timestamp("客户端处理线程已创建,当前连接数: %d\n", client_count); + } + + pthread_mutex_unlock(&client_mutex); + } + + return 0; +}