443 lines
13 KiB
Markdown
443 lines
13 KiB
Markdown
# 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<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
|
||
核心业务逻辑层,协调扫描任务的执行。
|
||
|
||
**接口:**
|
||
```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<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 协议。
|
||
|
||
**接口:**
|
||
```java
|
||
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 操作。
|
||
|
||
**接口:**
|
||
```java
|
||
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。
|
||
|
||
**接口:**
|
||
```java
|
||
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:**
|
||
```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;
|
||
}
|
||
```
|