我对popen(char *cmd,char *mode)的理解

本文详细介绍了popen函数的工作原理及使用方法。当模式为“r”时,父进程通过popen调用创建子进程并接收其标准输出;当模式为“w”时,父进程向子进程提供标准输入。值得注意的是,popen为半双工操作,不能同时用于输入和输出。

FILE *popen(char *cmd,char *mode)

如果 mode 是“r",通常是一个父进程调用popen函数,那么此时popen生成了一个子进程,子进程干的事情 就是cmd,然后做完这件事后,会把结果送进子进程的标准输出,而这个标准输出就对应着父进程的一个流文件指针,比如FILE *fd,fd=popen(cmd,"r")的话,子进程的标准输出就对应于父进程的fd了。


如果mode 是”w“的话,父进程调用popen函数,并且把父进程的某个文件的流文件指针对应到子进程的标准输入上,即父进程向子进程提供标准输入数据。例子:

FILE *fd,fd=popen(cmd,"w")。此时就把fd对应的流文件作为子进程的标准输入了。


注意:popen是半双工的。父进行不可能同时既为子进程提供标准输入,又接受子进程的标准输出。


参考文献:《UNIX 环境高级编程》 第二版。508页

#include "anti_jitter.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <sys/wait.h> #define MAX_LINE_LEN 512 /** 全局timeout变量声明 */ struct uloop_timeout timeout; /** MAC地址验证函数 */ bool is_valid_mac(const char *mac) { int colon_count = 0; const char *p = mac; while (*p) { if (isxdigit(*p) || *p == ':' || *p == '-') { if (*p == ':' || *p == '-') colon_count++; } else if (*p != ' ') { return false; } p++; } return (colon_count == 5); } /** 解析wlanconfig list输出 */ int parse_wlanconfig_output(const char *output, ClientInfo **clients) { if (!output || !clients) return 0; char *output_copy = strdup(output); if (!output_copy) return 0; char *lines[256]; int line_count = 0; char *save_ptr; /* 使用strtok_r分割输出为独立行 */ char *line = strtok_r(output_copy, "\n", &save_ptr); /* 逐行读取直到结束或达到最大行数 */ while (line && line_count < 4096) { lines[line_count++] = line; line = strtok_r(NULL, "\n", &save_ptr); } /* 初始化客户端列表和计数器 */ ClientInfo *list = NULL; int count = 0; ClientInfo *current = NULL; /* 从第1行开始解析(跳过表头) */ for (int i = 1; i < line_count; i++) { char *cur_line = lines[i]; /* 跳过空行和RSSI说明行 */ if (strlen(cur_line) == 0 || strstr(cur_line, "RSSI is combined")) continue; /* 检测客户端基本信息行(非缩进行) */ if (cur_line[0] != ' ') { /* 保存前一个客户端到列表 */ if (current) { /* 扩展客户端列表内存 */ list = realloc(list, (count + 1) * sizeof(ClientInfo)); /* 内存分配失败时跳转清理 */ if (!list) goto cleanup; list[count++] = *current; free(current); } /* 为新客户端分配内存 */ current = calloc(1, sizeof(ClientInfo)); if (!current) goto cleanup; /* 分割基本信息行为token */ char *tokens[128]; int token_count = 0; char *token = strtok(cur_line, " "); while (token && token_count < 128) { tokens[token_count++] = token; token = strtok(NULL, " "); } /* 验证token数量和MAC地址有效性 */ if (token_count < 14 || !is_valid_mac(tokens[0])) { free(current); current = NULL; continue; } /* 提取关键字段 */ strncpy(current->mac, tokens[0], 17); /* MAC地址(字段1) */ current->aid = atoi(tokens[1]); /* AID(字段2) */ current->rssi = atoi(tokens[5]); /* RSSI(字段6) */ strncpy(current->bandwidth_mode, tokens[token_count - 4], 31); /* 带宽模式(倒数第4字段) */ current->rxnss = atoi(tokens[token_count - 3]); /* RXNSS(倒数第3字段) */ current->txnss = atoi(tokens[token_count - 2]); /* TXNSS(倒数第2字段) */ /* 组合协商速率:TX速率(字段4)+ RX速率(字段5) */ snprintf(current->negotiated_rate, 63, "TX:%s RX:%s", tokens[3], tokens[4]); } /* 处理客户端详细信息行(缩进行) */ else if (current) { char *p = cur_line; /* 跳过行首空白字符 */ while (*p && isspace(*p)) p++; /* 查找键值分隔符冒号 */ char *colon = strchr(p, ':'); if (!colon) continue; /* 分割键值对 */ *colon = '\0'; /* 关键修复1: 去除键名尾部空格 */ char *key_end = colon; while (key_end > p && isspace(*(key_end - 1))) { key_end--; } *key_end = '\0'; // 截断键名尾部空格 char *value = colon + 1; /* 跳过值前的空白字符 */ while (*value && isspace(*value)) value++; /* 使用strncpy替代直接赋值 */ if (strcmp(p, "Operating band") == 0) { strncpy(current->operating_band, value, 31); current->operating_band[31] = '\0'; // 确保终止符 } else if (strcmp(p, "Max STA phymode") == 0) { strncpy(current->phymode, value, 31); current->phymode[31] = '\0'; } else if (strcmp(p, "SNR") == 0) { /* 关键修复4: 处理SNR值中的非数字字符 */ char *endptr; current->snr = strtol(value, &endptr, 10); if (endptr == value) { current->snr = 0; // 解析失败时设为默认值 } } } } /* 处理最后一个客户端信息 */ if (current) { list = realloc(list, (count + 1) * sizeof(ClientInfo)); if (list) list[count++] = *current; free(current); } /* 返回结果并清理资源 */ *clients = list; free(output_copy); return count; /* 错误处理区:释放所有分配的内存 */ cleanup: if (current) free(current); if (list) free(list); free(output_copy); return 0; } /** 打印客户端信息(移除5G过滤) */ void print_5g_clients(ClientInfo *clients, int count) { if (count <= 0) { printf("未发现无线终端\n"); return; } printf("5G终端列表 (%d个客户端):\n", count); for (int i = 0; i < count; i++) { printf("========= 客户端 %d =========\n", i+1); printf("MAC地址: %s\n", clients[i].mac); printf("AID: %d\n", clients[i].aid); printf("带宽模式: %s\n", clients[i].bandwidth_mode); printf("接收NSS: %d\n", clients[i].rxnss); printf("发送NSS: %d\n", clients[i].txnss); printf("RSSI: %d dBm\n", clients[i].rssi); printf("SNR: %d dB\n", clients[i].snr); printf("物理模式: %s\n", clients[i].phymode); printf("协商速率: %s\n", clients[i].negotiated_rate); printf("工作频段: %s\n", clients[i].operating_band); printf("============================\n\n"); } } /** 释放客户端列表内存 */ void free_client_list(ClientInfo *clients) { if (clients) free(clients); } /** 执行shell命令并获取输出 */ char *execute_command(const char *cmd) { FILE *fp = popen(cmd, "r"); if (!fp) return NULL; char buffer[4096]; char *result = malloc(65536); if (!result) { pclose(fp); return NULL; } result[0] = '\0'; while (fgets(buffer, sizeof(buffer), fp) != NULL) { strcat(result, buffer); } pclose(fp); return result; } /** 主循环定时器回调 */ void timer_cb(struct uloop_timeout *t) { printf("正在扫描5G客户端...\n"); char *output = execute_command("wlanconfig ath1 list"); if (output) { ClientInfo *clients = NULL; int count = parse_wlanconfig_output(output, &clients); if (count > 0) { print_5g_clients(clients, count); free_client_list(clients); } else { printf("未发现5G终端\n"); } free(output); } else { printf("命令执行失败\n"); } /* 重新设置定时器 */ uloop_timeout_set(&timeout, 3000); } int main(int argc, char **argv) { printf("5G客户端监控程序启动\n"); uloop_init(); timeout.cb = timer_cb; uloop_timeout_set(&timeout, 0); uloop_run(); uloop_done(); return 0; } #ifndef ANTI_JITTER_H #define ANTI_JITTER_H #include <libubox/uloop.h> #include <stdbool.h> #define MAX_BUFFER 4096 /** 客户端信息结构体 */ typedef struct { int aid; /**< 客户端关联ID */ char mac[18]; /**< MAC地址 */ char operating_band[32]; /**< Operating band值 */ char phymode[32]; /**< 物理模式原始字符串 */ char bandwidth_mode[32]; /**< 解析后的带宽模式 */ char negotiated_rate[64]; /**< 协商速率 */ int rxnss; /**< 接收NSS值 */ int txnss; /**< 发送NSS值 */ int rssi; /**< RSSI值 */ int snr; /**< SNR值 */ } ClientInfo; /** 全局定时器 */ extern struct uloop_timeout timeout; /** MAC地址格式验证 */ bool is_valid_mac(const char *str); /** 解析wlanconfig输出 */ int parse_wlanconfig_output(const char *output, ClientInfo **clients); /** 打印5G客户端信息 */ void print_5g_clients(ClientInfo *clients, int count); /** 定时器回调函数 */ void timer_cb(struct uloop_timeout *t); #endif /* ANTI_JITTER_H */ 字段解析部分没有问题了,现在修改几个点(代码逻辑不改了,编码风格也不要改) 1. 带宽模式: IEEE80211_MODE_11AXA_HE160,把带宽模式解读为160、80、40、20这样的整数,代表信道带宽的大小 2. 把程序拆分为anti_jitter.c(主事件循环) anti_jitter.h(头文件) client_inf.c(客户端信息维护)三个文件 3. 把客户端信息维护成一个全局变量
10-10
#ifndef ANTI_JITTER_H #define ANTI_JITTER_H #include <libubox/uloop.h> #include <stdbool.h> #define MAX_BUFFER 4096 /** 客户端信息结构体 */ typedef struct { int aid; /**< 客户端关联ID */ char mac[18]; /**< MAC地址 (xx:xx:xx:xx:xx:xx) */ char operating_band[32]; /**< Operating band值 */ char phymode[32]; /**< Max STA phymode */ char bandwidth_mode[32]; /**< 带宽模式 */ char negotiated_rate[64]; /**< 协商速率 */ int rxnss; /**< 接收NSS值 */ int txnss; /**< 发送NSS值 */ int rssi; /**< RSSI值 (dBm) */ int snr; /**< SNR值 (dB) */ } ClientInfo; /** 全局定时器 */ extern struct uloop_timeout timer; /** 检查MAC地址格式有效性 */ bool is_valid_mac(const char *str); /** 解析wlanconfig输出并提取客户端信息 */ int parse_wlanconfig_output(const char *output, ClientInfo **clients); /** 打印5G终端列表 */ void print_5g_clients(ClientInfo *clients, int count); /** 定时器回调函数 */ void timer_cb(struct uloop_timeout *t); #endif /* ANTI_JITTER_H */#include "anti_jitter.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <sys/wait.h> #define MAX_LINE_LEN 512 /** 全局timeout变量声明 */ struct uloop_timeout timeout; /** MAC地址验证函数 */ bool is_valid_mac(const char *mac) { int colon_count = 0; const char *p = mac; while (*p) { if (isxdigit(*p)) { /* 十六进制字符有效 */ } else if (*p == ':') { colon_count++; } else { return false; /* 非法字符 */ } p++; } return (colon_count == 5); /* 合法MAC应有5个冒号 */ } /** 精确解析wlanconfig输出 */ int parse_wlanconfig_output(const char *output, ClientInfo **clients) { if (!output || !clients || *output == '\0') return 0; char *copy = strdup(output); if (!copy) return 0; ClientInfo *client_list = NULL; int valid_count = 0; ClientInfo current_client = {0}; // 确保初始化为0 char *line = strtok(copy, "\n"); bool header_passed = false; while (line != NULL) { /* 清理行 */ char clean_line[MAX_LINE_LEN] = {0}; strncpy(clean_line, line, sizeof(clean_line)-1); char *start = clean_line; while (*start == ' ') start++; char *end = start + strlen(start) - 1; while (end > start && (*end == '\r' || *end == '\n' || *end == ' ')) *end-- = '\0'; if (strlen(start) == 0) continue; // 跳过空行 /* 阶段1: 识别表头 */ if (!header_passed) { if (strstr(start, "ADDR") && strstr(start, "TXRATE") && strstr(start, "CAPS")) { header_passed = true; line = strtok(NULL, "\n"); continue; } } /* 阶段2: 客户端行解析 */ if (header_passed) { char mac[18] = {0}; if (sscanf(start, "%17s", mac) == 1 && is_valid_mac(mac)) { /** 保存上一个客户端 */ if (strlen(current_client.mac) > 0) { ClientInfo *new_list = realloc(client_list, sizeof(ClientInfo) * (valid_count + 1)); if (new_list) { client_list = new_list; memcpy(&client_list[valid_count], &current_client, sizeof(ClientInfo)); valid_count++; } memset(&current_client, 0, sizeof(ClientInfo)); } /** 初始化新客户端 */ strncpy(current_client.mac, mac, sizeof(current_client.mac)-1); /** 关键字段解析优化 */ // 1. 物理模式 - 直接搜索IEEE80211_MODE char *phymode_ptr = strstr(start, "IEEE80211_MODE"); if (phymode_ptr) { char *end_ptr = strchr(phymode_ptr, ' '); if (end_ptr) { size_t len = end_ptr - phymode_ptr; strncpy(current_client.phymode, phymode_ptr, len); current_client.phymode[len] = '\0'; } else { strcpy(current_client.phymode, phymode_ptr); } } // 2. RXNSS/TXNSS - 精确位置查找 char *rxnss_ptr = strstr(start, "RXNSS"); if (rxnss_ptr) { char *value_ptr = rxnss_ptr + strlen("RXNSS"); current_client.rxnss = atoi(value_ptr); } char *txnss_ptr = strstr(start, "TXNSS"); if (txnss_ptr) { char *value_ptr = txnss_ptr + strlen("TXNSS"); current_client.txnss = atoi(value_ptr); } // 3. 协商速率 - 从TXRATE/RXRATE字段提取 char tx_rate[16] = {0}, rx_rate[16] = {0}; char *tx_ptr = strstr(start, "TXRATE"); char *rx_ptr = strstr(start, "RXRATE"); if (tx_ptr && rx_ptr) { // 定位TXRATE值 char *tx_val = tx_ptr + strlen("TXRATE"); while (*tx_val && !isdigit(*tx_val)) tx_val++; sscanf(tx_val, "%15s", tx_rate); // 定位RXRATE值 char *rx_val = rx_ptr + strlen("RXRATE"); while (*rx_val && !isdigit(*rx_val)) rx_val++; sscanf(rx_val, "%15s", rx_rate); // 格式化协商速率 snprintf(current_client.negotiated_rate, sizeof(current_client.negotiated_rate), "TX:%s RX:%s", tx_rate, rx_rate); } } } /* 阶段3: 属性块解析 */ if (strlen(current_client.mac) > 0) { // 带宽模式解析 if (strstr(start, "Operating band")) { char *colon = strchr(start, ':'); if (colon) { char *band = colon + 1; while (*band == ' ') band++; strncpy(current_client.operating_band, band, sizeof(current_client.operating_band)-1); } } // SNR解析 else if (strstr(start, "SNR")) { char *colon = strchr(start, ':'); if (colon) { current_client.snr = atoi(colon + 1); } } // RSSI解析 else if (strstr(start, "RSSI is combined")) { char *rssi_ptr = strstr(start, "RSSI"); if (rssi_ptr) { char *dash = strchr(rssi_ptr, '-'); if (dash) { current_client.rssi = atoi(dash); } } } } line = strtok(NULL, "\n"); } /** 保存最后一个客户端 */ if (strlen(current_client.mac) > 0) { ClientInfo *new_list = realloc(client_list, sizeof(ClientInfo) * (valid_count + 1)); if (new_list) { client_list = new_list; memcpy(&client_list[valid_count], &current_client, sizeof(ClientInfo)); valid_count++; } } *clients = client_list; free(copy); return valid_count; } /** 打印5GHz客户端信息 */ void print_5g_clients(ClientInfo *clients, int count) { printf("5G终端列表 (%d个客户端):\n", count); for (int i = 0; i < count; i++) { if (strstr(clients[i].operating_band, "5GHz") != NULL) { printf("========= 客户端 %d =========\n", i+1); printf("AID: %d\n", clients[i].aid); printf("MAC地址: %s\n", clients[i].mac); printf("带宽模式: %s\n", clients[i].operating_band); printf("物理模式: %s\n", clients[i].phymode); printf("协商速率: %s\n", clients[i].negotiated_rate); printf("RXNSS: %d\n", clients[i].rxnss); printf("TXNSS: %d\n", clients[i].txnss); printf("RSSI: %d\n", clients[i].rssi); printf("SNR: %d\n", clients[i].snr); printf("============================\n\n"); } } if (count == 0) { printf("未找到5G终端\n"); } } /** 释放客户端列表内存 */ void free_client_list(ClientInfo *clients) { if (clients) free(clients); } /** 执行shell命令并获取输出 */ char *execute_command(const char *cmd) { /* 原始实现保持不变 */ FILE *fp = popen(cmd, "r"); if (!fp) return NULL; char buffer[4096]; char *result = malloc(65536); if (!result) { pclose(fp); return NULL; } result[0] = '\0'; while (fgets(buffer, sizeof(buffer), fp) != NULL) { strcat(result, buffer); } pclose(fp); return result; } /** 主循环定时器回调 */ void timer_cb(struct uloop_timeout *t) { /* 原始实现保持不变 */ char *output = execute_command("wlanconfig ath1 list"); if (output) { ClientInfo *clients = NULL; int count = parse_wlanconfig_output(output, &clients); if (count > 0) { print_5g_clients(clients, count); free_client_list(clients); } else { printf("未找到5G终端\n"); } free(output); } /* 重新设置定时器 */ uloop_timeout_set(&timeout, 3000); /* 3秒间隔 */ } /** 初始化uloop */ void init_uloop(void) { uloop_init(); timeout.cb = timer_cb; uloop_timeout_set(&timeout, 0); /* 立即启动 */ uloop_run(); uloop_done(); } int main(int argc, char **argv) { init_uloop(); return 0; } root@Archer_GE550:~# wlanconfig ath1 list ADDR AID CHAN TXRATE RXRATE RSSI MINRSSI MAXRSSI IDLE TXSEQ RXSEQ CAPS XCAPS ACAPS ERP STATE MAXRATE(DOT11) HTCAPS VHTCAPS ASSOCTIME IEs MODE RXNSS TXNSS PSMODE 36:33:c1:e7:b6:33 1 40 1441M 1729M -42 -45 -25 1 0 65535 EPR EWBO NULL 0 b 2401900 AWPSM gGTRs 00:00:14 RSN WME IEEE80211_MODE_11AXA_HE160 2 2 1 LM NR BRP BRA BRT LCIM FTMRR RSSI is combined over chains in dBm Minimum Tx Power : 8 Maximum Tx Power : 22 HT Capability : Yes VHT Capability : Yes MU capable : Yes SNR : 53 Operating band : 5GHz Current Operating class : 129 Supported Operating classes : 81 83 84 115 116 117 118 119 120 124 125 126 127 128 130 Supported Rates(Mbps) : 6 9 12 18 24 36 48 54 Max STA phymode : IEEE80211_MODE_11AXA_HE160 MLO : No 上边是获取客户端信息的代码,下边是命令输出,代码运行异常,请修改字段解析函数
10-01
/** Client Information */ typedef struct { int aid; char mac[18]; char operating_band[32]; char phymode[32]; int bandwidth; char bandwidth_mode[32]; char negotiated_rate[64]; int rxnss; int txnss; int rssi; int snr; bool enab; bool gaming; bool state_debounce; int state_count; } ClientInfo; void timer_cb(struct uloop_timeout *t) { AntiJitterConfig config; if (parse_anti_jitter_config(config_path, &config) != 0) { printf("Error: Failed to parse configuration\n"); return; } // print_config(&config); if(strcmp(config.enable, "off") == 0) { uloop_timeout_set(&timeout, 3000); } char *active_macs[256] = {0}; int active_count = 0; char *output5g = execute_command("wlanconfig ath1 list"); if (output5g) { parse_wlanconfig_output(output5g, "5G", active_macs, &active_count); free(output5g); } char *output24g = execute_command("wlanconfig ath0 list"); if (output24g) { parse_wlanconfig_output(output24g, "2.4G", active_macs, &active_count); free(output24g); } cleanup_disconnected_clients(active_macs, active_count); for (int i = 0; i < active_count; i++) { free(active_macs[i]); } if(strcmp(config.mode, "Manual") == 0) { apply_manual_config(g_clients, g_client_count, config.stations, config.stations_count); } free_anti_jitter_config(&config); // char *output_appdpi = execute_command("cat /proc/app_dpi/app_record"); /* debug */ char *output_appdpi = strdup ( "1398 192.168.0.169 DA-11-D7-57-23-C3 1760511841 0 150 3824614 0\n" "1399 192.168.0.56 36:33:C1:E7:B6:33 1760511952 0 150 3824614 0\n" "1400 192.168.0.100 AB-CD-EF-12-34-56 1760512000 1760513000 150 3824614 0\n" ); int gaming_count = 0; char **mac_list = parse_app_record(output_appdpi, &gaming_count); record_gaming_state(g_clients, g_client_count, mac_list, gaming_count); // printf("Gaming stations:%d \n", gaming_count); // for (int i = 0; i < gaming_count; i++) // { // printf("%d. %s\n", i + 1, mac_list[i]); // } state_update(g_clients, g_client_count, config); if (g_client_count > 0) { print_clients(); } else { printf("未发现无线终端\n"); } uloop_timeout_set(&timeout, 3000); } char *execute_command(const char *cmd) { FILE *fp = popen(cmd, "r"); if (!fp) { return NULL; } char buffer[4096]; char *result = malloc(65536); if (!result) { pclose(fp); return NULL; } result[0] = '\0'; while (fgets(buffer, sizeof(buffer), fp) != NULL) { strcat(result, buffer); } pclose(fp); return result; } /* Parse the output of wlanconfig */ int parse_wlanconfig_output(const char *output, const char *band, char **active_macs, int *active_count) { if (!output) { return 0; } char *output_copy = strdup(output); if (!output_copy) { return 0; } char *lines[256]; int line_count = 0; char *save_ptr; char *line = strtok_r(output_copy, "\n", &save_ptr); while (line && line_count < 256) { lines[line_count++] = line; line = strtok_r(NULL, "\n", &save_ptr); } ClientInfo *new_clients = NULL; int new_client_count = 0; ClientInfo *current = NULL; bool is_new_client = false; for (int i = 1; i < line_count; i++) { char *cur_line = lines[i]; if (strlen(cur_line) == 0 || strstr(cur_line, "RSSI is combined")) { continue; } if (cur_line[0] != ' ') { char *tokens[128]; int token_count = 0; char *token = strtok(cur_line, " "); while (token && token_count < 128) { tokens[token_count++] = token; token = strtok(NULL, " "); } if (token_count < 14 || !is_valid_mac(tokens[0])) { if (current && is_new_client) { new_clients = realloc(new_clients, (new_client_count + 1) * sizeof(ClientInfo)); if (!new_clients) goto cleanup; new_clients[new_client_count++] = *current; free(current); } current = NULL; continue; } if (active_macs && active_count) { active_macs[*active_count] = strdup(tokens[0]); if (active_macs[*active_count]) { (*active_count)++; } } ClientInfo *existing = find_client_by_mac(tokens[0]); if (existing) { current = existing; is_new_client = false; } else { if (current && is_new_client) { new_clients = realloc(new_clients, (new_client_count + 1) * sizeof(ClientInfo)); if (!new_clients) goto cleanup; new_clients[new_client_count++] = *current; free(current); } current = calloc(1, sizeof(ClientInfo)); if (!current) goto cleanup; is_new_client = true; current->enab = false; current->gaming = false; current->state_debounce = false; current->state_count = 0; } strncpy(current->mac, tokens[0], sizeof(current->mac)-1); current->mac[sizeof(current->mac)-1] = '\0'; current->aid = atoi(tokens[1]); current->rssi = atoi(tokens[5]); if (token_count >= 14) { strncpy(current->bandwidth_mode, tokens[token_count - 4], sizeof(current->bandwidth_mode)-1); current->bandwidth_mode[sizeof(current->bandwidth_mode)-1] = '\0'; current->bandwidth = parse_bandwidth(current->bandwidth_mode); current->rxnss = atoi(tokens[token_count - 3]); current->txnss = atoi(tokens[token_count - 2]); snprintf(current->negotiated_rate, sizeof(current->negotiated_rate)-1, "TX:%s RX:%s", tokens[3], tokens[4]); current->negotiated_rate[sizeof(current->negotiated_rate)-1] = '\0'; } strncpy(current->operating_band, band, sizeof(current->operating_band)-1); current->operating_band[sizeof(current->operating_band)-1] = '\0'; } else if (current) { char *p = cur_line; while (*p && isspace(*p)) p++; char *colon = strchr(p, ':'); if (!colon) continue; *colon = '\0'; char *key_end = colon; while (key_end > p && isspace(*(key_end - 1))) key_end--; *key_end = '\0'; char *value = colon + 1; while (*value && isspace(*value)) value++; if (strcmp(p, "Max STA phymode") == 0) { strncpy(current->phymode, value, sizeof(current->phymode)-1); current->phymode[sizeof(current->phymode)-1] = '\0'; } else if (strcmp(p, "SNR") == 0) { char *endptr; current->snr = strtol(value, &endptr, 10); if (endptr == value) current->snr = 0; } } } if (current && is_new_client) { new_clients = realloc(new_clients, (new_client_count + 1) * sizeof(ClientInfo)); if (!new_clients) { free(current); goto cleanup; } new_clients[new_client_count++] = *current; free(current); } if (new_client_count > 0) { if (g_clients) { ClientInfo *merged = realloc(g_clients, (g_client_count + new_client_count) * sizeof(ClientInfo)); if (!merged) { free(new_clients); goto cleanup; } g_clients = merged; for (int i = 0; i < new_client_count; i++) { g_clients[g_client_count++] = new_clients[i]; } free(new_clients); } else { g_clients = new_clients; g_client_count = new_client_count; } } else if (new_clients) { free(new_clients); } free(output_copy); return new_client_count; cleanup: if (current && is_new_client) free(current); if (new_clients) free(new_clients); free(output_copy); return 0; } 修改clientinfo接口,增加丢包率和重传率指标,然后增加一个函数维护这个指标,在void timer_cb(struct uloop_timeout *t)里调用这个函数来维护每个client 的丢包率和重传率,具体获取方式如下(需要计算相邻时间间隔的发包数、丢包数、和重传数来进一步计算丢包率,重传率): root@Archer_GE550:/# apstats -s -m 36:33:c1:e7:b6:33 |grep "Tx Data Packets" Tx Data Packets = 132 Tx Data Packets per AC: root@Archer_GE550:/# apstats -s -m 36:33:c1:e7:b6:33 |grep "Tx Success Data Packets" Tx Success Data Packets = 131 root@Archer_GE550:/# apstats -s -m 36:33:c1:e7:b6:33 |grep "MSDU: Tx retry count" MSDU: Tx retry count = 21 root@Archer_GE550:/#
最新发布
10-25
wlanconfig ath1 list root@Archer_GE550:~# wlanconfig ath1 list ADDR AID CHAN TXRATE RXRATE RSSI MINRSSI MAXRSSI IDLE TXSEQ RXSEQ CAPS XCAPS ACAPS ERP STATE MAXRATE(DOT11) HTCAPS VHTCAPS ASSOCTIME IEs MODE RXNSS TXNSS PSMODE 3a:e8:3c:eb:a4:f9 2 40 58M 72M -56 -63 -50 272 0 65535 EPSs BRIf NULL 0 b 65000 P 0gR 00:21:10 RSN WME IEEE80211_MODE_11AXA_HE20 1 1 NR RSSI is combined over chains in dBm Minimum Tx Power : 0 Maximum Tx Power : 16 HT Capability : Yes VHT Capability : No MU capable : No SNR : 39 Operating band : 5GHz Current Operating class : 0 Supported Rates(Mbps) : 6 9 12 18 24 36 48 54 Max STA phymode : IEEE80211_MODE_11AXA_HE20 MLO : No 36:33:c1:e7:b6:33 1 40 1297M 309M -39 -44 -32 0 0 65535 EPR EWBO NULL 0 b 2401900 AWPSM gGTRs 00:00:10 RSN WME IEEE80211_MODE_11AXA_HE160 2 2 1 LM NR BRP BRA BRT LCIM FTMRR RSSI is combined over chains in dBm Minimum Tx Power : 8 Maximum Tx Power : 22 HT Capability : Yes VHT Capability : Yes MU capable : Yes SNR : 56 Operating band : 5GHz Current Operating class : 129 Supported Operating classes : 81 83 84 115 116 117 118 119 120 124 125 126 127 128 130 Supported Rates(Mbps) : 6 9 12 18 24 36 48 54 Max STA phymode : IEEE80211_MODE_11AXA_HE160 MLO : No root@Archer_GE550:~# 以上是wlanconfig ath1 list的输出修改以下代码,维护5G终端列表(请完成parse_wlanconfig_output函数,返回客户端的数量) 记住第一行(表头)的字段名(不用体现在代码里),读取每一个客户端的信息,客户端信息的第一行用空格分割数据,在对应位置找到mac地址,AID,带宽模式,NSS,RSSI,(例如从第一行可以看出,mac地址是第一个字段,AID是第二个,RSSI是第六个,以此类推) 然后在下边对应行读出SNR信息 注意:ath1就是5G网口,读出来的终端都是5G无线终端,无需再作判断 #include "anti_jitter.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <sys/wait.h> #define MAX_LINE_LEN 512 /** 全局timeout变量声明 */ struct uloop_timeout timeout; /** MAC地址验证函数 - 修复版本 */ bool is_valid_mac(const char *mac) { int colon_count = 0; const char *p = mac; while (*p) { if (isxdigit(*p) || *p == ':') { if (*p == ':') colon_count++; } else { return false; /* 非法字符 */ } p++; } return (colon_count == 5); /* 合法MAC应有5个冒号 */ } /** 解析wlanconfig输出 */ int parse_wlanconfig_output(const char *output, ClientInfo **clients) { } /** 打印5GHz客户端信息 */ void print_5g_clients(ClientInfo *clients, int count) { int found = 0; for (int i = 0; i < count; i++) { if (strstr(clients[i].operating_band, "5GHz") != NULL) { found++; printf("5G终端列表 (%d个客户端):\n", found); printf("========= 客户端 %d =========\n", found); printf("AID: %d\n", clients[i].aid); printf("MAC地址: %s\n", clients[i].mac); printf("带宽模式: %s\n", clients[i].operating_band); printf("物理模式: %s\n", clients[i].phymode); printf("协商速率: %s\n", clients[i].negotiated_rate); printf("RXNSS: %d\n", clients[i].rxnss); printf("TXNSS: %d\n", clients[i].txnss); printf("RSSI: %d\n", clients[i].rssi); printf("SNR: %d\n", clients[i].snr); printf("============================\n\n"); } } if (found == 0) { printf("未找到5G终端\n"); } } /** 释放客户端列表内存 */ void free_client_list(ClientInfo *clients) { if (clients) free(clients); } /** 执行shell命令并获取输出 */ char *execute_command(const char *cmd) { FILE *fp = popen(cmd, "r"); if (!fp) return NULL; char buffer[4096]; char *result = malloc(65536); if (!result) { pclose(fp); return NULL; } result[0] = '\0'; while (fgets(buffer, sizeof(buffer), fp) != NULL) { strcat(result, buffer); } pclose(fp); return result; } /** 主循环定时器回调 */ void timer_cb(struct uloop_timeout *t) { printf("正在扫描5G客户端...\n"); char *output = execute_command("wlanconfig ath1 list"); if (output) { ClientInfo *clients = NULL; int count = parse_wlanconfig_output(output, &clients); if (count > 0) { print_5g_clients(clients, count); free_client_list(clients); } else { printf("未找到任何客户端\n"); } free(output); } else { printf("命令执行失败\n"); } /* 重新设置定时器 */ uloop_timeout_set(&timeout, 3000); /* 3秒间隔 */ } int main(int argc, char **argv) { printf("5G客户端监控程序启动\n"); uloop_init(); timeout.cb = timer_cb; uloop_timeout_set(&timeout, 0); /* 立即启动 */ uloop_run(); uloop_done(); return 0; } #ifndef ANTI_JITTER_H #define ANTI_JITTER_H #include <libubox/uloop.h> #include <stdbool.h> #define MAX_BUFFER 4096 /** 客户端信息结构体 */ typedef struct { int aid; /**< 客户端关联ID */ char mac[18]; /**< MAC地址 (xx:xx:xx:xx:xx:xx) */ char operating_band[32]; /**< Operating band值 */ char phymode[32]; /**< Max STA phymode */ char bandwidth_mode[32]; /**< 带宽模式 */ char negotiated_rate[64]; /**< 协商速率 */ int rxnss; /**< 接收NSS值 */ int txnss; /**< 发送NSS值 */ int rssi; /**< RSSI值 (dBm) */ int snr; /**< SNR值 (dB) */ } ClientInfo; /** 全局定时器 */ extern struct uloop_timeout timer; /** 检查MAC地址格式有效性 */ bool is_valid_mac(const char *str); /** 解析wlanconfig输出并提取客户端信息 */ int parse_wlanconfig_output(const char *output, ClientInfo **clients); /** 打印5G终端列表 */ void print_5g_clients(ClientInfo *clients, int count); /** 定时器回调函数 */ void timer_cb(struct uloop_timeout *t); #endif /* ANTI_JITTER_H */
10-10
wlanconfig ath1 list root@Archer_GE550:~# wlanconfig ath1 list ADDR AID CHAN TXRATE RXRATE RSSI MINRSSI MAXRSSI IDLE TXSEQ RXSEQ CAPS XCAPS ACAPS ERP STATE MAXRATE(DOT11) HTCAPS VHTCAPS ASSOCTIME IEs MODE RXNSS TXNSS PSMODE 3a:e8:3c:eb:a4:f9 2 40 58M 72M -56 -63 -50 272 0 65535 EPSs BRIf NULL 0 b 65000 P 0gR 00:21:10 RSN WME IEEE80211_MODE_11NA_HT20 1 1 1 NR RSSI is combined over chains in dBm Minimum Tx Power : 0 Maximum Tx Power : 16 HT Capability : Yes VHT Capability : No MU capable : No SNR : 39 Operating band : 5GHz Current Operating class : 0 Supported Rates(Mbps) : 6 9 12 18 24 36 48 54 Max STA phymode : IEEE80211_MODE_11NA_HT20 MLO : No 36:33:c1:e7:b6:33 1 40 1297M 309M -39 -44 -32 0 0 65535 EPR EWBO NULL 0 b 2401900 AWPSM gGTRs 00:00:10 RSN WME IEEE80211_MODE_11AXA_HE160 2 2 1 LM NR BRP BRA BRT LCIM FTMRR RSSI is combined over chains in dBm Minimum Tx Power : 8 Maximum Tx Power : 22 HT Capability : Yes VHT Capability : Yes MU capable : Yes SNR : 56 Operating band : 5GHz Current Operating class : 129 Supported Operating classes : 81 83 84 115 116 117 118 119 120 124 125 126 127 128 130 Supported Rates(Mbps) : 6 9 12 18 24 36 48 54 Max STA phymode : IEEE80211_MODE_11AXA_HE160 MLO : No root@Archer_GE550:~# 以上是wlanconfig ath1 list的输出修改以下代码,维护5G终端列表 记住第一行(表头)的字段名(不用体现在代码里),读取每一个客户端的信息,客户端信息的第一行用空格分割数据,在对应位置找到mac地址,AID,带宽模式,NSS,RSSI,(例如从第一行可以看出,mac地址是第一个字段,AID是第二个,RSSI是第六个,以此类推) 然后在下边对应行读出SNR信息 注意:ath1就是5G网口,读出来的终端都是5G无线终端,无需再作判断 #include "anti_jitter.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <sys/wait.h> #define MAX_LINE_LEN 512 /** 全局timeout变量声明 */ struct uloop_timeout timeout; /** MAC地址验证函数 - 修复版本 */ bool is_valid_mac(const char *mac) { int colon_count = 0; const char *p = mac; while (*p) { if (isxdigit(*p) || *p == ':') { if (*p == ':') colon_count++; } else { return false; /* 非法字符 */ } p++; } return (colon_count == 5); /* 合法MAC应有5个冒号 */ } /** 解析wlanconfig输出 */ int parse_wlanconfig_output(const char *output, ClientInfo **clients) { if (!output || !clients || *output == '\0') return 0; char *copy = strdup(output); if (!copy) return 0; ClientInfo *client_list = NULL; int valid_count = 0; ClientInfo current_client = {0}; char *line = strtok(copy, "\n"); HeaderIndices indices = {-1}; bool in_client_block = false; bool header_parsed = false; while (line != NULL) { // 清理行 char *start = line; while (*start == ' ') start++; size_t len = strlen(start); while (len > 0 && (start[len-1] == '\r' || start[len-1] == '\n' || start[len-1] == ' ')) start[--len] = '\0'; if (len == 0) { line = strtok(NULL, "\n"); continue; } // 阶段1: 解析表头 if (!header_parsed && strstr(start, "ADDR") && strstr(start, "TXRATE")) { char *token; char *saveptr; int idx = 0; // 初始化索引位置 memset(&indices, -1, sizeof(HeaderIndices)); // 分割表头行 token = strtok_r(start, " ", &saveptr); while (token != NULL) { if (strcmp(token, "ADDR") == 0) indices.addr_idx = idx; else if (strcmp(token, "AID") == 0) indices.aid_idx = idx; else if (strcmp(token, "TXRATE") == 0) indices.txrate_idx = idx; else if (strcmp(token, "RXRATE") == 0) indices.rxrate_idx = idx; else if (strcmp(token, "RSSI") == 0) indices.rssi_idx = idx; else if (strcmp(token, "MODE") == 0) indices.mode_idx = idx; else if (strcmp(token, "RXNSS") == 0) indices.rxnss_idx = idx; else if (strcmp(token, "TXNSS") == 0) indices.txnss_idx = idx; token = strtok_r(NULL, " ", &saveptr); idx++; } header_parsed = true; } // 阶段2: 解析客户端行 if (header_parsed && is_valid_mac(start)) { // 保存前一个客户端 if (strlen(current_client.mac) > 0) { ClientInfo *new_list = realloc(client_list, sizeof(ClientInfo) * (valid_count + 1)); if (new_list) { client_list = new_list; client_list[valid_count] = current_client; valid_count++; } } // 初始化新客户端 memset(&current_client, 0, sizeof(ClientInfo)); in_client_block = true; // 分割客户端行 char *tokens[64]; int token_count = 0; char *token = strtok(start, " "); while (token != NULL && token_count < 64) { tokens[token_count] = token; token_count++; token = strtok(NULL, " "); } // 根据表头位置提取字段 if (indices.addr_idx >= 0 && indices.addr_idx < token_count) strncpy(current_client.mac, tokens[indices.addr_idx], sizeof(current_client.mac)-1); if (indices.aid_idx >= 0 && indices.aid_idx < token_count) current_client.aid = atoi(tokens[indices.aid_idx]); if (indices.rssi_idx >= 0 && indices.rssi_idx < token_count) current_client.rssi = atoi(tokens[indices.rssi_idx]); if (indices.txrate_idx >= 0 && indices.txrate_idx < token_count && indices.rxrate_idx >= 0 && indices.rxrate_idx < token_count) { snprintf(current_client.negotiated_rate, sizeof(current_client.negotiated_rate), "TX:%s RX:%s", tokens[indices.txrate_idx], tokens[indices.rxrate_idx]); } if (indices.mode_idx >= 0 && indices.mode_idx < token_count) strncpy(current_client.phymode, tokens[indices.mode_idx], sizeof(current_client.phymode)-1); if (indices.rxnss_idx >= 0 && indices.rxnss_idx < token_count) current_client.rxnss = atoi(tokens[indices.rxnss_idx]); if (indices.txnss_idx >= 0 && indices.txnss_idx < token_count) current_client.txnss = atoi(tokens[indices.txnss_idx]); } // 阶段3: 客户端属性块解析 if (in_client_block) { // 带宽模式提取 if (strstr(start, "Operating band")) { char *colon = strchr(start, ':'); if (colon) { char *band = colon + 1; while (*band == ' ') band++; strncpy(current_client.operating_band, band, sizeof(current_client.operating_band)-1); } } // SNR值提取 else if (strstr(start, "SNR")) { char *colon = strchr(start, ':'); if (colon) current_client.snr = atoi(colon + 1); } // 物理模式备用来源 else if (strstr(start, "Max STA phymode")) { char *colon = strchr(start, ':'); if (colon) { char *mode = colon + 1; while (*mode == ' ') mode++; if (strlen(current_client.phymode) == 0) { strncpy(current_client.phymode, mode, sizeof(current_client.phymode)-1); } } } // 结束客户端块 else if (strncmp(start, "RSSI is combined", 16) == 0) { in_client_block = false; } } line = strtok(NULL, "\n"); } // 保存最后一个客户端 if (strlen(current_client.mac) > 0) { ClientInfo *new_list = realloc(client_list, sizeof(ClientInfo) * (valid_count + 1)); if (new_list) { client_list = new_list; client_list[valid_count] = current_client; valid_count++; } } *clients = client_list; free(copy); return valid_count; } /** 打印5GHz客户端信息 */ void print_5g_clients(ClientInfo *clients, int count) { int found = 0; for (int i = 0; i < count; i++) { if (strstr(clients[i].operating_band, "5GHz") != NULL) { found++; printf("5G终端列表 (%d个客户端):\n", found); printf("========= 客户端 %d =========\n", found); printf("AID: %d\n", clients[i].aid); printf("MAC地址: %s\n", clients[i].mac); printf("带宽模式: %s\n", clients[i].operating_band); printf("物理模式: %s\n", clients[i].phymode); printf("协商速率: %s\n", clients[i].negotiated_rate); printf("RXNSS: %d\n", clients[i].rxnss); printf("TXNSS: %d\n", clients[i].txnss); printf("RSSI: %d\n", clients[i].rssi); printf("SNR: %d\n", clients[i].snr); printf("============================\n\n"); } } if (found == 0) { printf("未找到5G终端\n"); } } /** 释放客户端列表内存 */ void free_client_list(ClientInfo *clients) { if (clients) free(clients); } /** 执行shell命令并获取输出 */ char *execute_command(const char *cmd) { FILE *fp = popen(cmd, "r"); if (!fp) return NULL; char buffer[4096]; char *result = malloc(65536); if (!result) { pclose(fp); return NULL; } result[0] = '\0'; while (fgets(buffer, sizeof(buffer), fp) != NULL) { strcat(result, buffer); } pclose(fp); return result; } /** 主循环定时器回调 */ void timer_cb(struct uloop_timeout *t) { printf("正在扫描5G客户端...\n"); char *output = execute_command("wlanconfig ath1 list"); if (output) { ClientInfo *clients = NULL; int count = parse_wlanconfig_output(output, &clients); if (count > 0) { print_5g_clients(clients, count); free_client_list(clients); } else { printf("未找到任何客户端\n"); } free(output); } else { printf("命令执行失败\n"); } /* 重新设置定时器 */ uloop_timeout_set(&timeout, 3000); /* 3秒间隔 */ } int main(int argc, char **argv) { printf("5G客户端监控程序启动\n"); uloop_init(); timeout.cb = timer_cb; uloop_timeout_set(&timeout, 0); /* 立即启动 */ uloop_run(); uloop_done(); return 0; } #ifndef ANTI_JITTER_H #define ANTI_JITTER_H #include <libubox/uloop.h> #include <stdbool.h> #define MAX_BUFFER 4096 /** 客户端信息结构体 */ typedef struct { int aid; /**< 客户端关联ID */ char mac[18]; /**< MAC地址 (xx:xx:xx:xx:xx:xx) */ char operating_band[32]; /**< Operating band值 */ char phymode[32]; /**< Max STA phymode */ char bandwidth_mode[32]; /**< 带宽模式 */ char negotiated_rate[64]; /**< 协商速率 */ int rxnss; /**< 接收NSS值 */ int txnss; /**< 发送NSS值 */ int rssi; /**< RSSI值 (dBm) */ int snr; /**< SNR值 (dB) */ } ClientInfo; /** 全局定时器 */ extern struct uloop_timeout timer; /** 检查MAC地址格式有效性 */ bool is_valid_mac(const char *str); /** 解析wlanconfig输出并提取客户端信息 */ int parse_wlanconfig_output(const char *output, ClientInfo **clients); /** 打印5G终端列表 */ void print_5g_clients(ClientInfo *clients, int count); /** 定时器回调函数 */ void timer_cb(struct uloop_timeout *t); #endif /* ANTI_JITTER_H */
10-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值