当前位置: 首页 > news >正文

SpringBoot 网络流量抓包与分析系统

下面我将设计一个基于SpringBoot的网络流量抓包与实时分析系统。这个系统将能够捕获网络数据包,进行实时分析,并通过Web界面展示结果。

系统架构设计

用户界面 (Web)↑↓ HTTP/WebSocket
SpringBoot控制器层↑↓ 内部调用
流量分析服务层↑↓ 事件驱动
数据包捕获层 (Jpcap/Pcap4J)↑↓ 原始网络接口
网络设备

实现步骤

  1. 添加Maven依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- 网络抓包库 --><dependency><groupId>org.pcap4j</groupId><artifactId>pcap4j-core</artifactId><version>1.8.2</version></dependency><dependency><groupId>org.pcap4j</groupId><artifactId>pcap4j-packetfactory-static</artifactId><version>1.8.2</version></dependency>
</dependencies>
  1. 数据包捕获服务
@Service
public class PacketCaptureService {private static final Logger logger = LoggerFactory.getLogger(PacketCaptureService.class);private PcapHandle handle;private volatile boolean isCapturing = false;private final PacketProcessor packetProcessor;public PacketCaptureService(PacketProcessor packetProcessor) {this.packetProcessor = packetProcessor;}public void startCapture(String networkInterface) throws PcapNativeException, NotOpenException {if (isCapturing) {logger.warn("Capture is already running");return;}// 获取网络接口PcapNetworkInterface nif = Pcaps.getDevByName(networkInterface);// 打开接口handle = nif.openLive(65536, PromiscuousMode.PROMISCUOUS, 100);isCapturing = true;// 启动捕获线程new Thread(() -> {try {handle.loop(0, (Packet packet) -> {packetProcessor.processPacket(packet);});} catch (Exception e) {logger.error("Error during packet capture", e);}}).start();logger.info("Started packet capture on interface: {}", networkInterface);}public void stopCapture() {isCapturing = false;if (handle != null && handle.isOpen()) {handle.breakLoop();handle.close();}logger.info("Stopped packet capture");}public boolean isCapturing() {return isCapturing;}
}
  1. 数据包处理器
@Component
public class PacketProcessor {private static final Logger logger = LoggerFactory.getLogger(PacketProcessor.class);// 存储统计分析结果private final ConcurrentHashMap<String, TrafficStats> trafficStats = new ConcurrentHashMap<>();private final SimpMessagingTemplate messagingTemplate;public PacketProcessor(SimpMessagingTemplate messagingTemplate) {this.messagingTemplate = messagingTemplate;}public void processPacket(Packet packet) {if (packet.contains(IpV4Packet.class)) {IpV4Packet ipV4Packet = packet.get(IpV4Packet.class);String srcIp = ipV4Packet.getHeader().getSrcAddr().getHostAddress();String dstIp = ipV4Packet.getHeader().getDstAddr().getHostAddress();int length = packet.length();// 更新统计数据updateStats(srcIp, dstIp, length);// 实时发送到前端sendRealTimeUpdate(srcIp, dstIp, length);}}private void updateStats(String srcIp, String dstIp, int length) {// 更新源IP统计trafficStats.compute(srcIp, (ip, stats) -> {if (stats == null) {stats = new TrafficStats(ip);}stats.addOutgoingTraffic(length);return stats;});// 更新目标IP统计trafficStats.compute(dstIp, (ip, stats) -> {if (stats == null) {stats = new TrafficStats(ip);}stats.addIncomingTraffic(length);return stats;});}private void sendRealTimeUpdate(String srcIp, String dstIp, int length) {Map<String, Object> update = new HashMap<>();update.put("timestamp", System.currentTimeMillis());update.put("source", srcIp);update.put("destination", dstIp);update.put("length", length);messagingTemplate.convertAndSend("/topic/traffic", update);}public Map<String, TrafficStats> getTrafficStats() {return new HashMap<>(trafficStats);}
}@Data
@AllArgsConstructor
class TrafficStats {private String ipAddress;private long incomingBytes = 0;private long outgoingBytes = 0;private int packetCount = 0;public TrafficStats(String ipAddress) {this.ipAddress = ipAddress;}public void addIncomingTraffic(int bytes) {this.incomingBytes += bytes;this.packetCount++;}public void addOutgoingTraffic(int bytes) {this.outgoingBytes += bytes;this.packetCount++;}
}
  1. Web控制器
@RestController
@RequestMapping("/api/traffic")
public class TrafficController {private final PacketCaptureService captureService;private final PacketProcessor packetProcessor;public TrafficController(PacketCaptureService captureService, PacketProcessor packetProcessor) {this.captureService = captureService;this.packetProcessor = packetProcessor;}@PostMapping("/start")public ResponseEntity<String> startCapture(@RequestParam String interfaceName) {try {captureService.startCapture(interfaceName);return ResponseEntity.ok("Capture started on interface: " + interfaceName);} catch (Exception e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to start capture: " + e.getMessage());}}@PostMapping("/stop")public ResponseEntity<String> stopCapture() {captureService.stopCapture();return ResponseEntity.ok("Capture stopped");}@GetMapping("/stats")public Map<String, TrafficStats> getStats() {return packetProcessor.getTrafficStats();}@GetMapping("/interfaces")public List<String> getNetworkInterfaces() throws PcapNativeException {return Pcaps.findAllDevs().stream().map(PcapNetworkInterface::getName).collect(Collectors.toList());}
}
  1. WebSocket配置
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {config.enableSimpleBroker("/topic");config.setApplicationDestinationPrefixes("/app");}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/traffic-websocket").withSockJS();}
}
  1. 前端界面 (HTML + JavaScript)
<!DOCTYPE html>
<html>
<head><title>网络流量监控</title><script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script><script src="https://cdn.jsdelivr.net/npm/stompjs@2/lib/stomp.min.js"></script><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><style>body { font-family: Arial, sans-serif; margin: 20px; }.container { display: flex; flex-direction: column; gap: 20px; }.controls { display: flex; gap: 10px; align-items: center; }table { border-collapse: collapse; width: 100%; }th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }th { background-color: #f2f2f2; }.chart-container { position: relative; height: 300px; width: 100%; }</style>
</head>
<body><div class="container"><h1>网络流量监控系统</h1><div class="controls"><select id="interfaceSelect"><option value="">选择网络接口</option></select><button id="startBtn" onclick="startCapture()">开始抓包</button><button id="stopBtn" onclick="stopCapture()" disabled>停止抓包</button><span id="status">状态: 未启动</span></div><div><h2>实时流量</h2><div class="chart-container"><canvas id="trafficChart"></canvas></div></div><div><h2>流量统计</h2><table id="statsTable"><thead><tr><th>IP地址</th><th>流入流量 (字节)</th><th>流出流量 (字节)</th><th>数据包数量</th></tr></thead><tbody></tbody></table></div></div><script>let stompClient = null;let trafficChart = null;let chartData = {labels: [],datasets: [{label: '流量 (字节)',data: [],borderColor: 'rgb(75, 192, 192)',tension: 0.1}]};// 初始化页面window.onload = function() {// 获取网络接口列表fetch('/api/traffic/interfaces').then(response => response.json()).then(interfaces => {const select = document.getElementById('interfaceSelect');interfaces.forEach(iface => {const option = document.createElement('option');option.value = iface;option.textContent = iface;select.appendChild(option);});});// 初始化图表const ctx = document.getElementById('trafficChart').getContext('2d');trafficChart = new Chart(ctx, {type: 'line',data: chartData,options: {responsive: true,maintainAspectRatio: false,scales: {y: {beginAtZero: true}}}});};// 连接WebSocketfunction connectWebSocket() {const socket = new SockJS('/traffic-websocket');stompClient = Stomp.over(socket);stompClient.connect({}, function(frame) {console.log('Connected: ' + frame);stompClient.subscribe('/topic/traffic', function(message) {const trafficData = JSON.parse(message.body);updateTrafficChart(trafficData);});});}// 更新流量图表function updateTrafficChart(data) {const now = new Date().toLocaleTimeString();chartData.labels.push(now);chartData.datasets[0].data.push(data.length);// 保持最后20个数据点if (chartData.labels.length > 20) {chartData.labels.shift();chartData.datasets[0].data.shift();}trafficChart.update();}// 开始抓包function startCapture() {const interfaceName = document.getElementById('interfaceSelect').value;if (!interfaceName) {alert('请选择网络接口');return;}fetch(`/api/traffic/start?interfaceName=${encodeURIComponent(interfaceName)}`, {method: 'POST'}).then(response => response.text()).then(result => {document.getElementById('status').textContent = '状态: 运行中';document.getElementById('startBtn').disabled = true;document.getElementById('stopBtn').disabled = false;connectWebSocket();startUpdatingStats();}).catch(error => console.error('Error:', error));}// 停止抓包function stopCapture() {fetch('/api/traffic/stop', {method: 'POST'}).then(response => response.text()).then(result => {document.getElementById('status').textContent = '状态: 已停止';document.getElementById('startBtn').disabled = false;document.getElementById('stopBtn').disabled = true;if (stompClient !== null) {stompClient.disconnect();}clearInterval(statsInterval);}).catch(error => console.error('Error:', error));}// 定期更新统计数据let statsInterval;function startUpdatingStats() {statsInterval = setInterval(() => {fetch('/api/traffic/stats').then(response => response.json()).then(stats => {const tbody = document.querySelector('#statsTable tbody');tbody.innerHTML = '';for (const [ip, data] of Object.entries(stats)) {const row = document.createElement('tr');row.innerHTML = `<td>${data.ipAddress}</td><td>${data.incomingBytes}</td><td>${data.outgoingBytes}</td><td>${data.packetCount}</td>`;tbody.appendChild(row);}});}, 2000);}</script>
</body>
</html>

系统功能说明

  1. 网络接口选择:用户可以从下拉菜单中选择要监控的网络接口
  2. 流量捕获控制:可以启动和停止数据包捕获
  3. 实时流量展示:通过WebSocket实时推送流量数据,使用图表展示
  4. 流量统计分析:展示每个IP地址的流入/流出流量和数据包数量
  5. 数据持久化:可根据需要扩展,将流量数据保存到数据库

运行注意事项

  1. 需要安装WinPcap(Windows)或libpcap(Linux/Mac)等底层抓包库
  2. 在Linux系统上可能需要以root权限运行应用
  3. 可根据需要添加过滤器,只捕获特定协议或端口的流量

这个系统提供了基本的网络流量监控功能,可以根据实际需求进一步扩展,比如添加协议分析、流量告警、历史数据查询等功能。

http://www.dtcms.com/a/366616.html

相关文章:

  • DevOps平台选型指南:破解研发效率瓶颈,适配金融/政务/国产化场景的5大关键指标
  • 【数据可视化-108】2025年6月新能源汽车零售销量TOP10车企分析大屏(PyEcharts炫酷黑色主题可视化)
  • C#强制类型转换(显示转换)和安全类型转换
  • 激光频率梳 3D 轮廓测量 - 莫尔条纹光的工作原理及优缺点
  • 2025变现打法:AI+IP实现高效变现|创客匠人
  • Mysql杂志(九)
  • Agent Prompt工程:如何让智能体更“听话”?(实践指南)
  • 深度学习玩游戏, 模型玩游戏,大模型+游戏 llm+game, 机器学习玩游戏,人工智能游戏陪伴,模型陪玩游戏
  • 机器学习基础-day02-K近邻算法
  • 大数据框架Doris全面解析
  • 学习机器学习能看哪些书籍
  • 计算机毕业设计:基于Python的影评情感分析可视化推荐系统
  • 【嵌入式DIY实例-ESP32篇】-倾斜弹跳球游戏
  • 【CouponHub项目开发】使用RocketMQ5.x实现延时修改优惠券状态,并通过使用模板方法模式重构消息队列发送功能
  • Unity中,软遮罩SoftMaskForUGUI可移动遮罩形状实现方法
  • 阻抗、瞬时阻抗、特性阻抗的区别
  • AI重构出海营销:HeadAI如何用“滴滴模式”破解红人营销效率困局?
  • 元宇宙与教育变革:沉浸式学习重构知识获取与能力培养
  • 从关键词到语义理解:小陌引擎如何重构AI搜索优化逻辑?
  • 【RNN-LSTM-GRU】第三篇 LSTM门控机制详解:告别梯度消失,让神经网络拥有长期记忆
  • 《ConfigMap热更新失效的深度解剖与重构实践》
  • Java GcExcel V8.2 新版本:效率升级与功能突破
  • Excel ——INDEX + MATCH 组合
  • Loopback for Mac:一键打造虚拟音频矩阵,实现跨应用音频自由流转
  • Leetcode—3516. 找到最近的人【简单】
  • wps的excel如何转为谷歌在线表格
  • JAVA层的权限与SELinux的关系
  • 【Python基础】 14 Rust 与 Python 标识符命名规则与风格对比笔记
  • AI编程:重塑软件开发范式的三大支柱
  • 微信小程序-day4