# Design Document: AMT Network Scanner ## Overview 本设计文档描述了机房远程控制系统中 AMT 网络扫描功能的技术实现方案。该系统采用前后端分离架构,使用 Spring Boot 构建后端服务,Vue 3 构建前端界面。核心功能是通过 RMCP (Remote Management Control Protocol) Ping 协议扫描局域网中支持 Intel AMT 的设备,并使用异步多线程技术提高扫描效率。 系统将 Intel AMT SDK 中的 RMCPPing 模块移植到 Java 环境,实现跨平台的设备发现能力。扫描结果通过 WebSocket 实时推送到前端,提供流畅的用户体验。 ## Architecture ### 系统架构图 ``` ┌─────────────────────────────────────────────────────────────┐ │ Frontend (Vue 3) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Scan Config │ │ Progress Bar │ │ Device List │ │ │ │ Component │ │ Component │ │ Component │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ └──────────────────┴──────────────────┘ │ │ │ │ │ ┌───────▼────────┐ │ │ │ WebSocket │ │ │ │ Connection │ │ │ └───────┬────────┘ │ └────────────────────────────┼──────────────────────────────────┘ │ HTTP/WebSocket ┌────────────────────────────┼──────────────────────────────────┐ │ ┌───────▼────────┐ │ │ │ API Gateway │ │ │ │ (Controller) │ │ │ └───────┬────────┘ │ │ │ │ │ ┌─────────────┴─────────────┐ │ │ │ │ │ │ ┌───────▼────────┐ ┌───────▼────────┐ │ │ │ Scan Service │ │ Device Service │ │ │ └───────┬────────┘ └───────┬────────┘ │ │ │ │ │ │ ┌───────▼────────┐ ┌───────▼────────┐ │ │ │ RMCP Scanner │ │ Device Repo │ │ │ │ (Thread Pool) │ │ (JPA) │ │ │ └───────┬────────┘ └───────┬────────┘ │ │ │ │ │ │ ┌───────▼────────┐ ┌───────▼────────┐ │ │ │ AMT Detector │ │ Database │ │ │ │ (RMCP Ping) │ │ (MySQL) │ │ │ └────────────────┘ └────────────────┘ │ │ │ │ Backend (Spring Boot) │ └───────────────────────────────────────────────────────────────┘ ``` ### 技术栈 **后端:** - Spring Boot 3.x - Spring Web (RESTful API) - Spring WebSocket (实时通信) - Spring Data JPA (数据持久化) - MySQL 8.x (数据库) - Java 17+ - Lombok (简化代码) **前端:** - Vue 3 - Vite (构建工具) - Element Plus (UI 组件库) - Axios (HTTP 客户端) - Pinia (状态管理) ## Components and Interfaces ### Backend Components #### 1. ScanController 负责处理扫描相关的 HTTP 请求和 WebSocket 连接。 **接口:** ```java @RestController @RequestMapping("/api/scan") public class ScanController { // 启动扫描任务 @PostMapping("/start") ResponseEntity startScan(@RequestBody ScanRequest request); // 获取扫描任务状态 @GetMapping("/status/{taskId}") ResponseEntity getScanStatus(@PathVariable String taskId); // 取消扫描任务 @PostMapping("/cancel/{taskId}") ResponseEntity cancelScan(@PathVariable String taskId); } @Controller public class ScanWebSocketController { // WebSocket 端点,用于推送扫描进度 @MessageMapping("/scan/progress") @SendTo("/topic/scan/{taskId}") void sendProgress(ScanProgress progress); } ``` #### 2. ScanService 核心业务逻辑层,协调扫描任务的执行。 **接口:** ```java public interface ScanService { // 创建并启动扫描任务 String startScan(String networkSegment, String subnetMask); // 获取扫描任务状态 ScanStatus getStatus(String taskId); // 取消扫描任务 void cancelScan(String taskId); // 处理发现的设备 void handleDiscoveredDevice(AmtDevice device); } ``` #### 3. RmcpScanner 多线程扫描引擎,负责并发执行 IP 地址检测。 **接口:** ```java public class RmcpScanner { // 扫描指定网段 CompletableFuture scanNetwork( String networkSegment, String subnetMask, ScanProgressCallback callback ); // 检测单个 IP 是否支持 AMT CompletableFuture> detectDevice(String ipAddress); // 取消扫描 void cancelScan(String taskId); } ``` #### 4. AmtDetector AMT 设备检测器,实现 RMCP Ping 协议。 **接口:** ```java public class AmtDetector { // 发送 RMCP Ping 并解析响应 Optional ping(String ipAddress, int timeout); // 构建 RMCP Ping 数据包 byte[] buildRmcpPingPacket(); // 解析 RMCP Pong 响应 PlatformData parsePongResponse(byte[] response); } ``` #### 5. DeviceService 设备管理服务,负责设备的 CRUD 操作。 **接口:** ```java public interface DeviceService { // 保存设备 AmtDevice saveDevice(AmtDevice device); // 查询所有设备 List getAllDevices(); // 根据 IP 查询设备 Optional getDeviceByIp(String ipAddress); // 删除设备 void deleteDevice(Long deviceId); // 搜索设备 List searchDevices(String keyword); } ``` #### 6. DeviceRepository 数据访问层,使用 Spring Data JPA。 **接口:** ```java public interface DeviceRepository extends JpaRepository { Optional findByIpAddress(String ipAddress); List findByIpAddressContaining(String keyword); List findByProvisioningState(ProvisioningState state); } ``` ### Frontend Components #### 1. ScanConfigComponent 扫描配置组件,用户输入网段和子网掩码。 **Props & Events:** ```typescript interface ScanConfigProps { // 无 props } interface ScanConfigEmits { (e: 'start-scan', config: ScanConfig): void; } interface ScanConfig { networkSegment: string; // 例如: "192.168.1.0" subnetMask: string; // 例如: "255.255.255.0" 或 "/24" } ``` #### 2. ProgressBarComponent 进度条组件,显示扫描进度。 **Props:** ```typescript interface ProgressBarProps { taskId: string; progress: number; // 0-100 scannedCount: number; totalCount: number; foundDevices: number; status: 'running' | 'completed' | 'cancelled' | 'error'; } ``` #### 3. DeviceListComponent 设备列表组件,展示已发现的设备。 **Props & Events:** ```typescript interface DeviceListProps { devices: AmtDevice[]; loading: boolean; } interface DeviceListEmits { (e: 'delete-device', deviceId: number): void; (e: 'refresh'): void; } ``` ## Data Models ### Backend Data Models #### AmtDevice Entity ```java @Entity @Table(name = "amt_devices") @Data @NoArgsConstructor @AllArgsConstructor public class AmtDevice { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true, length = 15) private String ipAddress; @Column(nullable = false) private Integer majorVersion; @Column(nullable = false) private Integer minorVersion; @Enumerated(EnumType.STRING) @Column(nullable = false, length = 20) private ProvisioningState provisioningState; @Column(nullable = false) private LocalDateTime discoveredAt; @Column(nullable = false) private LocalDateTime lastSeenAt; @Column(nullable = false) private Boolean online; @Column(length = 100) private String hostname; @Column(length = 500) private String description; } ``` #### ProvisioningState Enum ```java public enum ProvisioningState { PRE("Pre-provisioning"), IN("In-provisioning"), POST("Post-provisioning"), UNKNOWN("Unknown"); private final String displayName; ProvisioningState(String displayName) { this.displayName = displayName; } public String getDisplayName() { return displayName; } } ``` #### PlatformData DTO ```java @Data @NoArgsConstructor @AllArgsConstructor public class PlatformData { private ProvisioningState provisioningState; private Integer majorVersion; private Integer minorVersion; } ``` #### ScanRequest DTO ```java @Data @NoArgsConstructor @AllArgsConstructor public class ScanRequest { @NotBlank(message = "Network segment is required") @Pattern(regexp = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", message = "Invalid IP address format") private String networkSegment; @NotBlank(message = "Subnet mask is required") private String subnetMask; // 支持 "255.255.255.0" 或 "/24" 格式 } ``` #### ScanTaskResponse DTO ```java @Data @NoArgsConstructor @AllArgsConstructor public class ScanTaskResponse { private String taskId; private String status; private Integer totalIpCount; private LocalDateTime startTime; } ``` #### ScanProgress DTO ```java @Data @NoArgsConstructor @AllArgsConstructor public class ScanProgress { private String taskId; private Integer scannedCount; private Integer totalCount; private Integer foundDevices; private Double progressPercentage; private String currentIp; private AmtDevice latestDevice; // 最新发现的设备 } ``` #### ScanStatus DTO ```java @Data @NoArgsConstructor @AllArgsConstructor public class ScanStatus { private String taskId; private String status; // RUNNING, COMPLETED, CANCELLED, ERROR private Integer scannedCount; private Integer totalCount; private Integer foundDevices; private LocalDateTime startTime; private LocalDateTime endTime; private String errorMessage; } ``` ### Frontend Data Models #### AmtDevice Interface ```typescript export interface AmtDevice { id: number; ipAddress: string; majorVersion: number; minorVersion: number; provisioningState: 'PRE' | 'IN' | 'POST' | 'UNKNOWN'; discoveredAt: string; lastSeenAt: string; online: boolean; hostname?: string; description?: string; } ``` #### ScanConfig Interface ```typescript export interface ScanConfig { networkSegment: string; subnetMask: string; } ``` #### ScanProgress Interface ```typescript export interface ScanProgress { taskId: string; scannedCount: number; totalCount: number; foundDevices: number; progressPercentage: number; currentIp: string; latestDevice?: AmtDevice; } ```