execve_hook/tests/test_concurrent_client.c

211 lines
6.1 KiB
C

#include "../src/client.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
/**
* 并发测试客户端 - 用于测试多个客户端并发访问服务端
*
* 用法:
* ./test_concurrent_client <log_file_path> <线程数> [延迟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 <log_file_path> <线程数> [延迟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;
}
}