#include "../src/client.h" #include #include #include #include #include #include /** * 并发测试客户端 - 用于测试多个客户端并发访问服务端 * * 用法: * ./test_concurrent_client <线程数> [延迟ms] * * 示例: * ./test_concurrent_client /tmp/test_error.log 10 # 10个并发线程 * ./test_concurrent_client /tmp/test_error.log 20 100 # 20个线程,每个延迟100ms */ // 线程参数结构 typedef struct { int thread_id; const char *log_path; int delay_ms; // 启动前延迟(毫秒) int success; // 执行结果 } thread_args_t; // 统计信息 typedef struct { int total; int success; int failed; pthread_mutex_t mutex; } stats_t; static stats_t g_stats = {0, 0, 0, PTHREAD_MUTEX_INITIALIZER}; /** * 工作线程函数 */ void *worker_thread(void *arg) { thread_args_t *args = (thread_args_t *)arg; // 如果设置了延迟,先等待 if (args->delay_ms > 0) { usleep(args->delay_ms * 1000); } // 模拟不同的命令和参数 char *commands[] = { "/usr/bin/python3", "/usr/bin/ls", "/bin/bash", "/usr/bin/grep" }; const char *filename = commands[args->thread_id % 4]; // 构造测试参数 char arg1[64], arg2[64]; snprintf(arg1, sizeof(arg1), "arg1_thread_%d", args->thread_id); snprintf(arg2, sizeof(arg2), "arg2_thread_%d", args->thread_id); char *test_argv[] = { "command", arg1, arg2, NULL }; char *test_envp[] = { "PATH=/usr/bin:/bin", "HOME=/home/test", "THREAD_ID=test", NULL }; printf("[线程 %d] 开始发送请求: %s\n", args->thread_id, filename); // 调用客户端函数 int result = seeking_solutions(filename, test_argv, test_envp, args->log_path, &STDOUT_FILENO); args->success = (result == 0); // 更新统计信息 pthread_mutex_lock(&g_stats.mutex); if (result == 0) { g_stats.success++; printf("[线程 %d] ✓ 成功\n", args->thread_id); } else { g_stats.failed++; printf("[线程 %d] ✗ 失败 (返回值: %d)\n", args->thread_id, result); } pthread_mutex_unlock(&g_stats.mutex); return NULL; } /** * 打印使用说明 */ void print_usage(const char *prog_name) { fprintf(stderr, "用法: %s <线程数> [延迟ms]\n", prog_name); fprintf(stderr, "\n参数说明:\n"); fprintf(stderr, " log_file_path - 日志文件路径\n"); fprintf(stderr, " 线程数 - 并发线程数量 (1-1000)\n"); fprintf(stderr, " 延迟ms - 可选,每个线程启动前的延迟(毫秒)\n"); fprintf(stderr, "\n示例:\n"); fprintf(stderr, " %s /tmp/test.log 10 # 10个并发线程\n", prog_name); fprintf(stderr, " %s /tmp/test.log 50 100 # 50个线程,每个延迟100ms\n", prog_name); } int main(int argc, char *argv[]) { if (argc < 3) { print_usage(argv[0]); return 1; } const char *log_path = argv[1]; int num_threads = atoi(argv[2]); int delay_ms = (argc >= 4) ? atoi(argv[3]) : 0; // 验证参数 if (num_threads <= 0 || num_threads > 1000) { fprintf(stderr, "错误: 线程数必须在 1-1000 之间\n"); return 1; } printf("====== 并发测试开始 ======\n"); printf("socket地址: %s\n", SOCKET_PATH); printf("日志路径: %s\n", log_path); printf("并发线程数: %d\n", num_threads); printf("启动延迟: %d ms\n", delay_ms); printf("========================\n\n"); // 分配线程资源 pthread_t *threads = malloc(sizeof(pthread_t) * num_threads); thread_args_t *args = malloc(sizeof(thread_args_t) * num_threads); if (!threads || !args) { fprintf(stderr, "错误: 内存分配失败\n"); free(threads); free(args); return 1; } // 初始化统计信息 g_stats.total = num_threads; g_stats.success = 0; g_stats.failed = 0; // 记录开始时间 struct timespec start_time, end_time; clock_gettime(CLOCK_MONOTONIC, &start_time); // 创建并启动所有线程 printf("创建 %d 个线程...\n\n", num_threads); for (int i = 0; i < num_threads; i++) { args[i].thread_id = i; args[i].log_path = log_path; args[i].delay_ms = delay_ms; args[i].success = 0; if (pthread_create(&threads[i], NULL, worker_thread, &args[i]) != 0) { fprintf(stderr, "错误: 创建线程 %d 失败\n", i); // 继续创建其他线程 } } // 等待所有线程完成 printf("等待所有线程完成...\n\n"); for (int i = 0; i < num_threads; i++) { pthread_join(threads[i], NULL); } // 记录结束时间 clock_gettime(CLOCK_MONOTONIC, &end_time); // 计算耗时 double elapsed = (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec - start_time.tv_nsec) / 1e9; // 打印统计结果 printf("\n====== 测试结果统计 ======\n"); printf("总线程数: %d\n", g_stats.total); printf("成功: %d (%.1f%%)\n", g_stats.success, g_stats.total > 0 ? (g_stats.success * 100.0 / g_stats.total) : 0); printf("失败: %d (%.1f%%)\n", g_stats.failed, g_stats.total > 0 ? (g_stats.failed * 100.0 / g_stats.total) : 0); printf("总耗时: %.3f 秒\n", elapsed); printf("平均每个请求: %.3f 毫秒\n", g_stats.total > 0 ? (elapsed * 1000 / g_stats.total) : 0); printf("吞吐量: %.1f 请求/秒\n", elapsed > 0 ? (g_stats.total / elapsed) : 0); printf("========================\n"); // 清理资源 free(threads); free(args); pthread_mutex_destroy(&g_stats.mutex); // 返回结果 if (g_stats.failed > 0) { printf("\n✗ 测试完成,但有 %d 个请求失败\n", g_stats.failed); return 1; } else { printf("\n✓ 所有测试通过!\n"); return 0; } }