#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcap.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>#define SAMPLE_COUNT 0 // 0表示无限采样
#define TARGET_MAX 32
#define INTERVAL 2 // 采样间隔(秒)typedef struct {const char *ip;int port;unsigned long long bytes_sent;unsigned long long bytes_recv;double send_mbps;double recv_mbps;
} target_t;target_t targets[TARGET_MAX];
int target_count = 0;
int link_offset = 14;
volatile int running = 1;void signal_handler(int sig) {running = 0;
}void add_target(const char *ip, int port) {if(target_count >= TARGET_MAX) {fprintf(stderr, "Too many targets!\n");exit(1);}targets[target_count].ip = ip;targets[target_count].port = port;targets[target_count].bytes_sent = 0;targets[target_count].bytes_recv = 0;targets[target_count].send_mbps = 0.0;targets[target_count].recv_mbps = 0.0;target_count++;
}int get_link_offset(pcap_t *handle) {int linktype = pcap_datalink(handle);if(linktype == DLT_EN10MB) return 14;else if(linktype == DLT_LINUX_SLL) return 16;else {fprintf(stderr, "Unsupported datalink type: %d\n", linktype);exit(1);}
}void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {(void)user;if (h->len < link_offset + 20) return;struct ip *ip_hdr = (struct ip*)(bytes + link_offset);if(ip_hdr->ip_v != 4) return;int ip_hdr_len = ip_hdr->ip_hl * 4;if (h->len < link_offset + ip_hdr_len + 20) return;struct tcphdr *tcp_hdr = (struct tcphdr*)((u_char*)ip_hdr + ip_hdr_len);char src_ip[16], dst_ip[16];inet_ntop(AF_INET, &ip_hdr->ip_src, src_ip, sizeof(src_ip));inet_ntop(AF_INET, &ip_hdr->ip_dst, dst_ip, sizeof(dst_ip));// 使用标准的TCP头字段名int src_port = ntohs(tcp_hdr->source);int dst_port = ntohs(tcp_hdr->dest);for(int i = 0; i < target_count; i++) {// 本机发向目标if(strcmp(dst_ip, targets[i].ip) == 0 && dst_port == targets[i].port) {targets[i].bytes_sent += h->len;}// 目标发向本机if(strcmp(src_ip, targets[i].ip) == 0 && src_port == targets[i].port) {targets[i].bytes_recv += h->len;}}
}void print_header() {printf("\033[2J\033[H");printf("================================================================================\n");printf(" 实时带宽监控 (基于libpcap) - 端口: 9092\n");printf("================================================================================\n");printf("%-20s %-8s %-12s %-12s %-8s\n", "IP地址", "端口", "发送(Mbps)", "接收(Mbps)", "总带宽(Mbps)");printf("--------------------------------------------------------------------------------\n");
}void print_stats() {double total_send_mbps = 0.0;double total_recv_mbps = 0.0;int active_targets = 0;for(int i = 0; i < target_count; i++) {double total_mbps = targets[i].send_mbps + targets[i].recv_mbps;printf("%-20s %-8d %-12.2f %-12.2f %-8.2f\n",targets[i].ip, targets[i].port,targets[i].send_mbps,targets[i].recv_mbps,total_mbps);total_send_mbps += targets[i].send_mbps;total_recv_mbps += targets[i].recv_mbps;if (targets[i].send_mbps > 0 || targets[i].recv_mbps > 0) {active_targets++;}}printf("--------------------------------------------------------------------------------\n");printf("总计: %d个目标 | 总发送: %.2f Mbps | 总接收: %.2f Mbps | 总带宽: %.2f Mbps\n",active_targets, total_send_mbps, total_recv_mbps, total_send_mbps + total_recv_mbps);printf("================================================================================\n");printf("按 Ctrl+C 停止监控\n");
}int main() {signal(SIGINT, signal_handler);// 添加目标 IP:Portadd_target("10.252.12.100", 9092);add_target("10.252.134.67", 9092);add_target("10.252.134.68", 9092);add_target("10.252.134.69", 9092);add_target("10.252.134.70", 9092);add_target("10.252.134.71", 9092);add_target("10.52.16.68", 9092);add_target("10.52.16.69", 9092);add_target("10.52.16.70", 9092);add_target("10.52.16.71", 9092);add_target("10.52.16.72", 9092);add_target("10.252.12.83", 9092);add_target("10.252.12.84", 9092);add_target("10.252.12.85", 9092);add_target("10.252.12.86", 9092);add_target("10.252.12.87", 9092);add_target("10.252.12.88", 9092);add_target("10.252.12.89", 9092);add_target("10.252.145.44", 9092);add_target("10.252.12.99", 9092);char errbuf[PCAP_ERRBUF_SIZE];// 直接使用 eth0const char *iface = "eth0";// 显示可用网卡pcap_if_t *alldevs;if (pcap_findalldevs(&alldevs, errbuf) == 0) {printf("可用网卡:\n");for(pcap_if_t *d = alldevs; d; d = d->next) {printf(" %s", d->name);if (d->description) printf(" (%s)", d->description);printf("\n");}pcap_freealldevs(alldevs);}printf("使用网卡: %s\n", iface);pcap_t *handle = pcap_open_live(iface, 65536, 1, 1000, errbuf);if(!handle) {fprintf(stderr, "pcap_open_live failed on %s: %s\n", iface, errbuf);fprintf(stderr, "请检查网卡名称是否正确,或尝试使用 'any'\n");return 1;}link_offset = get_link_offset(handle);// 构建 BPF 过滤器char filter_exp[2048] = "tcp and (";for(int i = 0; i < target_count; i++) {char tmp[64];snprintf(tmp, sizeof(tmp), "host %s and port %d", targets[i].ip, targets[i].port);if (i > 0) strcat(filter_exp, " or ");strcat(filter_exp, tmp);}strcat(filter_exp, ")");printf("使用过滤器: %s\n", filter_exp);struct bpf_program fp;if(pcap_compile(handle, &fp, filter_exp, 1, PCAP_NETMASK_UNKNOWN) == -1) {fprintf(stderr, "pcap_compile failed: %s\n", pcap_geterr(handle));pcap_close(handle);return 1;}if(pcap_setfilter(handle, &fp) == -1) {fprintf(stderr, "pcap_setfilter failed: %s\n", pcap_geterr(handle));pcap_close(handle);return 1;}printf("开始监控 %d 个目标,采样间隔: %d 秒...\n", target_count, INTERVAL);printf("按 Ctrl+C 停止监控\n\n");sleep(2);int sample_num = 0;unsigned long long prev_sent[TARGET_MAX], prev_recv[TARGET_MAX];for(int i = 0; i < target_count; i++) {prev_sent[i] = targets[i].bytes_sent;prev_recv[i] = targets[i].bytes_recv;}while(running) {sample_num++;time_t start = time(NULL);while(time(NULL) - start < INTERVAL && running) {int ret = pcap_dispatch(handle, 100, packet_handler, NULL);if (ret == -1) {fprintf(stderr, "pcap_dispatch error: %s\n", pcap_geterr(handle));break;}usleep(1000);}if (!running) break;for(int i = 0; i < target_count; i++) {unsigned long long sent_diff = targets[i].bytes_sent - prev_sent[i];unsigned long long recv_diff = targets[i].bytes_recv - prev_recv[i];targets[i].send_mbps = (sent_diff * 8.0) / INTERVAL / 1000000.0;targets[i].recv_mbps = (recv_diff * 8.0) / INTERVAL / 1000000.0;prev_sent[i] = targets[i].bytes_sent;prev_recv[i] = targets[i].bytes_recv;}print_header();print_stats();if (SAMPLE_COUNT > 0 && sample_num >= SAMPLE_COUNT) {break;}}pcap_close(handle);printf("\n监控已停止。共采样 %d 次。\n", sample_num);return 0;
}