基于 Leptos + Rust WASM 前端和 Elysia.js + Bun 后端的网络拓扑仿真平台,类似 eNSP / Cisco Packet Tracer。
- 拖拽式拓扑编辑 — 从设备库拖拽路由器、交换机、主机、服务器、防火墙、云、无线AP 到画布
- 设备连线 — 支持铜缆、光纤、串口、无线等多种链路类型,可配置带宽/延迟/丢包率
- 连线工具 — 切换连线模式后依次点击两个设备即可创建链路
- 设备删除 — 选中设备后点击删除按钮,自动移除关联链路
- 拓扑管理 — 支持保存/加载拓扑到后端数据库
- WebGL2 实例化渲染 — 使用
WebGl2RenderingContext+ instanced drawing 高性能渲染大量设备节点和链路 - 视口裁剪 — 只渲染可见区域内的设备和链路,支持大规模拓扑
- 四叉树聚合 — 远距离视图下自动聚合临近设备为集群节点
- HTML 覆盖层 — 设备名称标签通过 HTML overlay 渲染,支持 CSS 样式
- 网格背景 — 自适应缩放的网格线
- 浮动窗口设备配置 — 双击设备打开可拖动、可缩放的浮动配置窗口,支持多开
- 单击选中 — 单击设备仅选中高亮(黄色轮廓),可拖动移动位置
- 画布操作 — 鼠标拖拽平移、滚轮缩放(以光标为中心)
- 窗口管理 — 窗口自动置顶,点 "x" 关闭,右下角拖动缩放
| 协议 | 说明 |
|---|---|
| ARP | 地址解析协议,缓存/请求/应答/gratuitous ARP |
| ICMP | Echo request/reply,TTL 超时 |
| DHCP | 客户端 FSM (Init→Selecting→Requesting→Bound→Renewing) |
| OSPF | 邻居状态机 (Down→Init→2Way→ExStart→Exchange→Loading→Full),Hello/DBD/LSR/LSU/LSAck,Dijkstra SPF |
| BGP | Peering FSM (Idle→Connect→OpenSent→OpenConfirm→Established) |
| TCP | 11 状态 FSM,3 次握手/4 次挥手,序列号跟踪 |
| UDP | Socket 跟踪,端口复用 |
| DNS | A/AAAA/PTR/MX/TXT 查询,本地设备名解析 |
| HTTP | HTTP/HTTPS 请求响应模拟,WebSocket 升级 |
RIP(距离向量,30s 更新)、IGMP、SNMP、Telnet、FTP、SMTP、SSH、SSL/TLS
GRE、L2TP、SCTP、PIM、VRRP、RSVP、ESP、AH、ICMPv6、RIPng、NTP、Syslog、RADIUS、TFTP、SIP、RTP、RTCP、SSDP、Kerberos、LDAP、POP3、IMAP、LLDP、STP、MPLS、PPPoE、DHCPv6、LDP、SOCKS 等。每个协议生成正确的 EtherType/IP 协议号/端口号/hex dump。
- Static — 静态路由
- RIP — 距离向量路由,split horizon,infinity=16
- OSPF — 链路状态路由,Dijkstra SPF 最短路径计算
- EIGRP — 增强型内部网关路由
- BGP — 边界网关协议,AS 间路由
| 厂商/系统 | 格式 | 说明 |
|---|---|---|
| Cisco | IOS | interface GigabitEthernet / router ospf |
| 华为 | VRP | sysname / interface GE |
| 华三 | Comware | interface Bridge-Aggregation / ip route-static |
| 锐捷 | RGOS | enable password (无 service timestamps) |
| Linux | ip addr | inet / link/ether / default via |
| Debian/Ubuntu | interfaces | iface eth0 inet static / address |
| CentOS/RHEL | ifcfg | BOOTPROTO=static / IPADDR= |
| Netplan | YAML | network: / ethernets: / addresses: |
| iwd | INI | [Settings] / [IPv4] |
| NetworkManager | keyfile | [connection] / [ipv4] |
| MikroTik | RouterOS | /ip address add / /interface |
| Juniper | JunOS | system { / set system host-name |
| Windows | netsh | netsh interface ip set address |
| Windows | PowerShell | New-NetIPAddress / Set-DnsClientServerAddress |
| OpenWrt | UCI | config interface / option ipaddr |
| JSON | JSON | 设备配置 JSON 格式 |
支持自动检测格式和手动选择厂商。导出时可选择目标格式。
- 每设备独立日志缓冲区(最多 500 条)
- 支持按协议过滤:全部 / ARP / ICMP / DHCP / TCP / UDP / DNS / HTTP / OSPF / BGP / SSH / TLS / SNMP / FTP / SMTP / 系统
- 实时抓包显示:源/目标 IP、端口、协议、长度、信息
- 协议分层树:以太网 → IP → TCP/UDP → 应用层
- 十六进制转储
- TCP 标志位显示(SYN、ACK、PSH、FIN、RST)
- 过滤栏(按协议/源/目标过滤)
- 自动滚动到底部
- 链路状态:Up(绿色)、Down(红色)、Congested(黄色)
- 接口标签页中可手动切换链路连接/断开
- 断开的链路在拓扑图中标红显示
- 拥塞检测:基于带宽利用率自动标记
- 独立页面
/congestion,显示链路带宽利用率
| 层级 | 技术 |
|---|---|
| 后端框架 | Elysia.js + Bun |
| 前端框架 | Leptos 0.7 (CSR) |
| 编译目标 | WebAssembly (wasm32-unknown-unknown) |
| 渲染 | WebGL2 (WebGl2RenderingContext + instanced drawing) |
| 路由 | leptos_router (path! 宏) |
| 序列化 | serde + serde-wasm-bindgen |
| 实时通信 | WebSocket (gloo-net / web-sys) |
| 构建工具 | Trunk (前端) / Bun (后端) |
network-sim/
├── src/
│ ├── lib.rs # App 入口 + 路由定义
│ ├── models/
│ │ ├── mod.rs # 数据模型 (NetworkDevice, NetworkLink, Packet, LinkStatus)
│ │ └── log.rs # 设备日志 (DeviceLog, LogLevel)
│ ├── state/
│ │ └── mod.rs # AppState 状态管理 (RwSignal, 浮动窗口管理)
│ ├── renderer/
│ │ ├── mod.rs # WebGL2 渲染引擎 (实例化绘制、视口裁剪)
│ │ ├── camera.rs # 相机 (平移/缩放/世界-屏幕坐标转换)
│ │ ├── quadtree.rs # 四叉树 (空间索引、可见性查询、聚合)
│ │ ├── batch.rs # 实例化批次 (InstanceBatch)
│ │ └── shaders.rs # GLSL 着色器 (quad + line)
│ ├── simulation/
│ │ └── mod.rs # 模拟引擎 (tick 循环、数据包传输、拥塞检测)
│ ├── protocols/ # 协议仿真模块
│ │ ├── mod.rs # 协议常量、模块注册
│ │ ├── arp.rs # ARP 状态机
│ │ ├── icmp.rs # ICMP echo
│ │ ├── dhcp.rs # DHCP 客户端 FSM
│ │ ├── ospf.rs # OSPF 邻居 + Dijkstra SPF
│ │ ├── bgp.rs # BGP peering FSM
│ │ ├── rip.rs # RIP 距离向量
│ │ ├── routing.rs # 路由表管理、最优路由选择
│ │ ├── tcp.rs # TCP 连接 FSM (11 状态)
│ │ ├── udp.rs # UDP socket 跟踪
│ │ ├── transport.rs # 端口复用、端口分配
│ │ ├── dns.rs # DNS 解析
│ │ ├── http_sim.rs # HTTP/HTTPS 模拟
│ │ ├── igmp.rs # IGMP
│ │ ├── snmp_sim.rs # SNMP
│ │ ├── telnet.rs # Telnet
│ │ ├── ftp.rs # FTP
│ │ ├── smtp.rs # SMTP
│ │ ├── ssh.rs # SSH
│ │ ├── ssl.rs # SSL/TLS
│ │ ├── decode.rs # 40+ 协议信息表
│ │ └── stubs.rs # Tier 3 报文生成器
│ ├── config/ # 厂商配置导入导出
│ │ ├── mod.rs # ConfigFormat 枚举、auto_parse、export_format
│ │ └── vendors/
│ │ ├── mod.rs # 厂商模块注册
│ │ ├── cisco.rs # Cisco IOS
│ │ ├── huawei.rs # 华为 VRP
│ │ ├── h3c.rs # 华三 Comware
│ │ ├── ruijie.rs # 锐捷 RGOS
│ │ ├── linux_net.rs # Linux ip addr
│ │ ├── debian.rs # Debian/Ubuntu interfaces
│ │ ├── centos.rs # CentOS/RHEL ifcfg
│ │ ├── netplan.rs # Netplan YAML
│ │ ├── iwd.rs # iwd
│ │ ├── nm.rs # NetworkManager
│ │ ├── mikrotik.rs # MikroTik RouterOS
│ │ ├── juniper.rs # Juniper JunOS
│ │ ├── win_netsh.rs # Windows netsh
│ │ ├── win_ps.rs # Windows PowerShell
│ │ ├── openwrt.rs # OpenWrt UCI
│ │ └── json.rs # JSON
│ └── components/
│ ├── mod.rs # 组件模块声明
│ ├── canvas.rs # 拓扑画布 (WebGL2 渲染、拖拽、双击、连线工具)
│ ├── sidebar.rs # 设备库侧边栏 + 工具按钮
│ ├── properties.rs # 浮动窗口设备配置 (拖动/缩放/多开)
│ ├── topology_manager.rs # 拓扑保存/加载管理
│ ├── traffic.rs # 流量分析面板 (嵌入拓扑视图)
│ ├── traffic_capture.rs # Wireshark 风格流量分析器 (/traffic)
│ └── congestion.rs # 拥塞分析 (/congestion)
├── server/
│ ├── index.ts # Elysia 后端:REST API、WebSocket、46 协议流量生成
│ ├── package.json
│ └── tsconfig.json
├── style/
│ └── main.css # Catppuccin Mocha 暗色主题 + 全部 UI 样式
├── public/ # 静态资源目录
├── Cargo.toml # Rust 依赖
├── Cargo.lock
├── Trunk.toml # Trunk 构建配置
└── index.html # HTML 入口
# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 添加 WASM 目标
rustup target add wasm32-unknown-unknown
# 安装 Trunk (WASM 构建工具)
cargo install trunk
# 安装 Bun (后端运行时)
curl -fsSL https://bun.sh/install | bash
# 重新加载 shell 环境变量
source ~/.bashrc # 或 source ~/.zshrccd server
bun install
bun run index.ts
# 后端运行在 http://localhost:3001# 在项目根目录新开一个终端
trunk serve --port 3000
# 前端开发服务器运行在 http://localhost:3000每次代码改完后需要重启服务(trunk 不会自动检测 CSS/静态文件变更,后端代码变更也不会热重载):
# 停止旧进程
pkill -f "trunk serve"
pkill -f "bun.*server/index"
# 重新启动
cd server && bun run index.ts &
trunk serve --port 3000-
安装 Rust
下载 rustup-init.exe,双击安装。安装时选择默认选项即可。
安装完成后打开新的终端(PowerShell 或 CMD),验证:
rustc --version cargo --version
-
添加 WASM 目标
rustup target add wasm32-unknown-unknown
-
安装 Trunk
cargo install trunk
-
安装 Bun
在 PowerShell 中执行:
irm bun.sh/install.ps1 | iex
安装完成后关闭并重新打开终端,验证:
bun --version
cd path\to\network-sim\server
bun install
bun run index.ts
# 后端运行在 http://localhost:3001# 在项目根目录新开一个终端
cd path\to\network-sim
trunk serve --port 3000
# 前端开发服务器运行在 http://localhost:3000每次代码改完后需要重启服务。先关闭两个终端(Ctrl+D 或关闭终端窗口),再按上述步骤重新启动后端和前端。
如果要在另一台 Windows 机器上运行,可以将项目打包传输过去:
-
打包项目(在 macOS 上执行)
# 排除平台相关的构建产物 cd /path/to/ tar czf network-sim.tar.gz \ --exclude='target/' \ --exclude='server/node_modules/' \ --exclude='.claude/' \ --exclude='.git/' \ --exclude='*.db' --exclude='*.db-shm' --exclude='*.db-wal' \ network-sim/
-
传输到远程 Windows 机器
sshpass -p <密码> scp network-sim.tar.gz <用户>@<IP>:network-sim.tar.gz
-
在远程 Windows 机器上解压
tar xzf network-sim.tar.gz
-
安装工具链(见上方 Windows 安装步骤)
-
启动服务
cd network-sim\server bun install Start-Process -NoNewWindow -FilePath "bun" -ArgumentList "run", "index.ts" cd .. Start-Process -NoNewWindow -FilePath "trunk" -ArgumentList "serve", "--port", "3000"
# 构建前端
trunk build --release
# 构建产物输出到 dist/ 目录
# 后端可直接运行
bun run server/index.tsGET/POST /topology— 拓扑导入/导出GET/POST/PATCH/DELETE /devices— 设备 CRUDGET/POST/PATCH/DELETE /links— 链路 CRUDPOST /simulation/start|stop— 模拟控制GET /simulation/status— 模拟状态POST /diagnostics/ping|traceroute|send-packet— 网络诊断GET /traffic/captures?limit=&protocol=&source=&destination=— Wireshark 风格流量捕获(支持过滤)GET /traffic/captures/:id— 单条流量详情GET /traffic/overview|links/:id|protocols|flow— 流量统计
/ws/sim/stream— 模拟数据流/ws/sim/events— 模拟事件/ws/traffic/stream— 实时流量推送
后端每 500ms(2Hz)自动生成 46 种协议流量:
- ARP 请求/应答、DNS 查询(53)、TCP 分段(SYN/ACK/PSH/FIN/RST)
- HTTP 请求(GET/POST/PUT/DELETE)、ICMP Echo、UDP 流(Syslog/SNMP/NTP)
- BGP Keepalive(179)、OSPF Hello、RIP Response
- Tier 3 协议随机选择生成
| 路径 | 功能 |
|---|---|
/ |
拓扑图(设备编辑 + 模拟) |
/traffic |
Wireshark 风格流量分析器 |
/congestion |
拥塞分析 |
/zabbix-comparison |
ODT vs Zabbix 对比实验 |
/cacti-comparison |
ODT vs Cacti 对比实验 |
AppState在App组件中通过provide_context(AppState::init())创建,子组件通过use_context::<AppState>().unwrap()访问- Canvas 使用
Rc<RefCell<...>>管理可变交互状态(而非RwSignal),避免 Leptos 响应式销毁问题 - 在响应式跟踪上下文外使用
.with_untracked()/.get_untracked() - 在
Effect体外部对NodeRef使用.get_untracked() - Canvas 渲染函数接受可选的
link_preview: Option<(f32,f32,f32,f32)>用于虚线预览 Effect::new配合initialized标志用于一次性 Canvas 初始化- ResizeObserver 监听容器实现响应式 Canvas 尺寸
- 路由定义使用
path!宏:<Route path=path!("/traffic") view=TrafficCaptureView /> - 导航使用
<a>标签(<A>不支持class属性) - WebSocket 回调中读取 signal 最新值需用
get_untracked() NodeRef不支持HtmlTableSectionElement等 web-sys 类型,需用StoredValue配合on:ref回调view!宏中闭包需要Send,Rc<Cell>不满足,用signal+get_untracked替代- Elysia 的
readyState行为异常,直接send+try-catch捕获错误更可靠 - 每次代码改完后重启 trunk(
pkill -f "trunk serve"再重新启动),trunk 不会自动检测 CSS/静态文件变更