13 KiB
13 KiB
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 连接。
接口:
@RestController
@RequestMapping("/api/scan")
public class ScanController {
// 启动扫描任务
@PostMapping("/start")
ResponseEntity<ScanTaskResponse> startScan(@RequestBody ScanRequest request);
// 获取扫描任务状态
@GetMapping("/status/{taskId}")
ResponseEntity<ScanStatus> getScanStatus(@PathVariable String taskId);
// 取消扫描任务
@PostMapping("/cancel/{taskId}")
ResponseEntity<Void> cancelScan(@PathVariable String taskId);
}
@Controller
public class ScanWebSocketController {
// WebSocket 端点,用于推送扫描进度
@MessageMapping("/scan/progress")
@SendTo("/topic/scan/{taskId}")
void sendProgress(ScanProgress progress);
}
2. ScanService
核心业务逻辑层,协调扫描任务的执行。
接口:
public interface ScanService {
// 创建并启动扫描任务
String startScan(String networkSegment, String subnetMask);
// 获取扫描任务状态
ScanStatus getStatus(String taskId);
// 取消扫描任务
void cancelScan(String taskId);
// 处理发现的设备
void handleDiscoveredDevice(AmtDevice device);
}
3. RmcpScanner
多线程扫描引擎,负责并发执行 IP 地址检测。
接口:
public class RmcpScanner {
// 扫描指定网段
CompletableFuture<ScanResult> scanNetwork(
String networkSegment,
String subnetMask,
ScanProgressCallback callback
);
// 检测单个 IP 是否支持 AMT
CompletableFuture<Optional<AmtDevice>> detectDevice(String ipAddress);
// 取消扫描
void cancelScan(String taskId);
}
4. AmtDetector
AMT 设备检测器,实现 RMCP Ping 协议。
接口:
public class AmtDetector {
// 发送 RMCP Ping 并解析响应
Optional<PlatformData> ping(String ipAddress, int timeout);
// 构建 RMCP Ping 数据包
byte[] buildRmcpPingPacket();
// 解析 RMCP Pong 响应
PlatformData parsePongResponse(byte[] response);
}
5. DeviceService
设备管理服务,负责设备的 CRUD 操作。
接口:
public interface DeviceService {
// 保存设备
AmtDevice saveDevice(AmtDevice device);
// 查询所有设备
List<AmtDevice> getAllDevices();
// 根据 IP 查询设备
Optional<AmtDevice> getDeviceByIp(String ipAddress);
// 删除设备
void deleteDevice(Long deviceId);
// 搜索设备
List<AmtDevice> searchDevices(String keyword);
}
6. DeviceRepository
数据访问层,使用 Spring Data JPA。
接口:
public interface DeviceRepository extends JpaRepository<AmtDevice, Long> {
Optional<AmtDevice> findByIpAddress(String ipAddress);
List<AmtDevice> findByIpAddressContaining(String keyword);
List<AmtDevice> findByProvisioningState(ProvisioningState state);
}
Frontend Components
1. ScanConfigComponent
扫描配置组件,用户输入网段和子网掩码。
Props & Events:
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:
interface ProgressBarProps {
taskId: string;
progress: number; // 0-100
scannedCount: number;
totalCount: number;
foundDevices: number;
status: 'running' | 'completed' | 'cancelled' | 'error';
}
3. DeviceListComponent
设备列表组件,展示已发现的设备。
Props & Events:
interface DeviceListProps {
devices: AmtDevice[];
loading: boolean;
}
interface DeviceListEmits {
(e: 'delete-device', deviceId: number): void;
(e: 'refresh'): void;
}
Data Models
Backend Data Models
AmtDevice Entity
@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
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
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PlatformData {
private ProvisioningState provisioningState;
private Integer majorVersion;
private Integer minorVersion;
}
ScanRequest DTO
@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
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScanTaskResponse {
private String taskId;
private String status;
private Integer totalIpCount;
private LocalDateTime startTime;
}
ScanProgress DTO
@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
@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
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
export interface ScanConfig {
networkSegment: string;
subnetMask: string;
}
ScanProgress Interface
export interface ScanProgress {
taskId: string;
scannedCount: number;
totalCount: number;
foundDevices: number;
progressPercentage: number;
currentIp: string;
latestDevice?: AmtDevice;
}