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

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.xdnf.cn/news/19910.html

相关文章:

  • 【RNN-LSTM-GRU】第一篇 序列建模基础:理解数据的“顺序”之力
  • Mac 使用 softhsm
  • 革新光纤锁模技术:《Light: Science Applications》报道纳米腔增强型可饱和吸收器
  • 质量管理里常见的缩写QA、QC、QE都是什么意思?
  • 彻底搞懂面向对象分析(OOA)
  • Linux内存管理章节一:深入浅出Linux内存管理:从物理内存到ARM32的用户与内核空间
  • 逻辑回归基础
  • .NET GcPDF V8.2 新版本:人工智能 PDF 处理
  • Spring Boot 根据配置优雅的决定实现类
  • Meshroom 2025.1.0安装及使用参数模板介绍:二维图片转三维重建
  • 因为对象装箱拆箱导致的空指针异常
  • C#强制类型转换(显示转换)和安全类型转换
  • 野火STM32Modbus主机读取寄存器/线圈失败(三)-尝试将存贮事件的地方改成数组(非必要解决方案)(附源码)
  • VBA中类的解读及应用第二十七讲:利用类完成查找的方案-5
  • SVT-AV1 svt_aom_motion_estimation_kernel 函数分析
  • 详细学习计划
  • 百度前端社招面经
  • 云手机运行是否消耗自身流量?
  • Docker(④Shell脚本)
  • 【RNN-LSTM-GRU】第五篇 序列模型实战指南:从选型到优化与前沿探索
  • 应对反爬:使用Selenium模拟浏览器抓取12306动态旅游产品
  • 40,.Ansible角色(roles)
  • 具身智能多模态感知与场景理解:视觉探索
  • 如何本地编译servicecomb-java-chassis
  • Focal Loss
  • Elasticsearch 8 中 Nested 数据类型的使用方法
  • 【文献解读】ceRNA机制研究经典思路
  • Spring Boot项目中MySQL索引失效的常见场景与解决方案
  • 从群体偏好到解构对齐:大模型强化学习从GRPO到DAPO的“认知”进化
  • 【高并发内存池】四、中心缓存的设计