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

Rust 实战四 | Traui2+Vue3+Rspack 开发桌面应用:通配符掩码计算器

封面

往期回顾

  • Rust 实战三 | HTTP 服务开发及 Web 框架推荐
  • Rust 实战二 | 开发简易版命令行工具 grep
  • Rust 实战一 | 用 RustRover 开发猜数字游戏
  • Rust 安装与版本更新

代码开源地址:https://github.com/0604hx/rust-journey、通配符掩码计算器


学习一门编程语言,总归会往 GUI 上面琢磨一些想法,关于 Rust 的GUI 可以看我往期的文章:Rust 语言 GUI 用户界面框架汇总。

今天终于到 Tauri 的实践环节啦,我们将使用 Tauri2+Vue3 开发一个简易小工具:通配符掩码计算器。

需求概述

为什么是通配符掩码计算器?

某天我看同事使用了一款小巧的软件,计算 IP 地址范围(如下图),觉得很有意思。寻思这个工具很实用,功能实现不难,很适合拿来做编程语言的练习项目。

上述截图是软件的其中一项功能,详细的介绍请见:推荐一款子网掩码计算神器。

关于通配符掩码

通配符掩码(Wildcard Mask)是网络技术中用于匹配 IP 地址范围的特殊标识,常见于路由协议(如 OSPF、EIGRP)和访问控制列表(ACL)中。它与子网掩码的作用类似,但逻辑相反,核心是通过0 和 1 的组合来定义 “需要精确匹配的位” 和 “可忽略的位”。

通配符掩码的基本规则

通配符掩码由 32 位二进制数组成(对应 IPv4 地址),每一位的含义如下:

  • 0:表示该位必须精确匹配(与目标 IP 地址的对应位完全相同)。
  • 1:表示该位可忽略(不关心目标 IP 地址的对应位是 0 还是 1)。

简言之:0 = 必须匹配,1 = 任意匹配

参考模板

  • tauri-vue-template:Fully configured project template for Tauri and Vue 3 w/ TypeScript and CI.

实施环节

工具主要主要功能就是根据用户输入的IP地址通配符掩码,计算匹配的 IP 地址,同时也提供发送到记事本,即创建一个同目录下的temp.txt并写入相应的内容后调用系统的记事本打开。

交互界面我们直接抄作业,做了简单的布局调整。

基础 UI 框架

我们的用户界面是基于 Vue3+Naive UI 实现的,刚开始还用不到 Tauri,先把界面框架搭建出来。下面是代码的结构:

代码结构
执行 pnpm i 安装依赖后,再通过pnpm ui运行 web 项目,即可看到如下界面。

运行截图

加入 Tauri

前置要求

这里以windows为例,其他系统请见Tauri Prerequisites。

Tauri 使用 Microsoft C++ 生成工具进行开发以及 Microsoft Edge WebView2。这两者都是在 Windows 上进行开发所必需的。

按照以下步骤安装所需的依赖项:

  1. 下载并安装Microsoft C++ 生成工具,在安装过程中,选中“使用 C++ 的桌面开发”选项;
  2. 安装 WebView 2,注意:该组件已安装在 Windows 10(从版本 1803 开始)和更高版本的 Windows 上。如果你正在这些版本之一上进行开发,则可以跳过此步骤。

使用 tauri-cli 改造项目

因为我们已经有了 web 项目,只需要加入 Tauri 相关依赖即可。

  1. 安装依赖:pnpm add -D @tauri-apps/cli@latest安装依赖
  2. 通过 tauri 在现有的基础上初始化项目:pnpm tauri init
  3. 此时,我们的项目中创建一个 src-tauri 目录,其中包含了重要的 Tauri 配置文件。
    src-tauri目录
    关于 src-tauri 的几个重要文件:
  • tauri.conf.json 是 Tauri 的主要配置文件,它包含从应用程序标识符到开发服务器 URL 的所有内容,该文件也是 Tauri CLI 查找 Rust 项目的标记, 详见Tauri Config。
  • capabilities/ 配置在 JavaScript 代码中运行使用的权限,详见https://tauri.app/security/。
  • src/lib.rs 包含 Rust 代码和移动入口点(标有 #[cfg_attr(mobile, tauri::mobile_entry_point)] 的函数),之所以跟 main.rs 分开,是因为要编译为移动版本中的库。
  • src/main.rs 是桌面的主入口点,我们在 main 中运行 tauri_app_lib::run() 以使用与移动端相同的入口点,因此为了简单起见,不要修改此文件,而是修改 src/lib.rs

通过 Tauri 启动项目

我们通过 pnpm tauri dev 即可以 tauri 方式启动现有项目,请注意第一次执行该命令,需要一个比较漫长的资源下载过程。


不久之后,我们就看到 tauri 程序窗口🎉。

再看看 src-tauri,竟然有 3.96GB 之大😮。

异常情况

1、无法加载 mspdbcore.dll
如果执行过程中碰到LINK : fatal error LNK1171: 无法加载 mspdbcore.dll (错误代码: 1455),请检查Microsoft C++ 生成工具是否正确安装。

2、out of memory

在这里插入图片描述
3、Error calling dlltool ‘dlltool.exe’: program not found
Windows 下 Tauri(Rust 编译)缺少交叉编译工具 的典型错误,原因是 Rust 在 Windows 上编译带有某些依赖的项目(尤其是用到 GNU 工具链)时,需要 dlltool.exe,而这个工具默认不会自带。

这个问题通常发生在:

  1. 你安装的是 x86_64-pc-windows-gnu 工具链(GNU 版本),不是 MSVC 版本
  2. 或者 Tauri 依赖的某个 crate 在构建时调用了 GNU 工具链(比如一些用 C 编写的库)
rustup install stable-x86_64-pc-windows-msvc
rustup default stable-x86_64-pc-windows-msvc

4、linker link.exe not found

请检查Microsoft C++ 生成工具是否正确安装,安装时勾选:

  • 使用 C++ 的桌面开发(Desktop development with C++)
  • 在右边的“安装详细信息”中确保勾选:
    • MSVC v143 或更高版本
    • Windows 10/11 SDK
    • C++ CMake 工具(可选)

tauri 打包

执行pnpm tauri build 即可。


最终产物 exe 为 8.2MB(其中前端打包后的体积为 0.3MB),相比 electron 的200MB可谓是瘦骨嶙峋😄。
如果是 Tauri 1.x,体积更小,基础功能在 5MB 内。

打包瘦身

[profile.release]
codegen-units = 1   # 减少代码生成单元以提高优化效果
lto = true          # 链接时优化(Link Time Optimization)
opt-level = "z"     # Prioritizes small binary size. Use `3` if you prefer speed,z to optimize for size, and s for something in-between.
panic = "abort"     # 遇到 panic 直接终止,不包含回溯信息
strip = true        # 去除符号表和调试信息

通过上述配置,我们的 exe 瘦身到 3144KB 👍,如果进一步设置opt-level="z"则可以做到2748KB

业务逻辑

终于到这一步了,我们需要真正实现工具的功能,计算通配符掩码可以直接在前端(用 JavaScript 实现),也可以使用后端 Rust 实现,考虑到计算量可能比较大(模糊掩码位较大时),这里选择 Rust 实现。

tauri 前后端交互

开始前,我们先做个简单的示例。开始前,我们需要确保已经安装了交互依赖pnpm i -D @tauri-apps/api

// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name:String)-> String {format!("Hi, {}, this's greet from Tauri!", name)
}#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {tauri::Builder::default().invoke_handler(tauri::generate_handler![greet]).run(tauri::generate_context!()).expect("error while running tauri application");
}
// src/App.vueimport { invoke } from '@tauri-apps/api/core'const greet = ()=>{invoke("greet", { name:"集成显卡"}).then(msg=>message.success("来自后端回复:"+msg))
}

掩码计算

/// 将 Ipv4Addr 转换为 32 位整数
fn ip_to_u32(ip: Ipv4Addr) -> u32 {let octets = ip.octets();((octets[0] as u32) << 24) |((octets[1] as u32) << 16) |((octets[2] as u32) << 8) |(octets[3] as u32)
}/// 将 32 位整数转换为 Ipv4Addr
fn u32_to_ip(n: u32) -> Ipv4Addr {Ipv4Addr::new(((n >> 24) & 0xFF) as u8,((n >> 16) & 0xFF) as u8,((n >> 8) & 0xFF) as u8,(n & 0xFF) as u8,)
}/// 计算与给定 IP 地址和通配符掩码匹配的所有 IP 地址
fn calculate_matching_ips(ip: Ipv4Addr, wildcard_mask: Ipv4Addr) -> Vec<Ipv4Addr> {// 将 IP 和通配符掩码转换为 32 位整数let ip_int = ip_to_u32(ip);let mask_int = ip_to_u32(wildcard_mask);// 计算固定位和可变位// 固定位:通配符掩码中为 0 的位,必须精确匹配// 可变位:通配符掩码中为 1 的位,可以是 0 或 1let fixed_bits = ip_int & !mask_int;let variable_mask = mask_int;// 计算可变位的数量let variable_bits_count = variable_mask.count_ones() as usize;// 检查可变位数量,避免生成过多 IP 地址导致性能问题if variable_bits_count > 20 {eprintln!("错误:通配符掩码包含太多可变位({}位),可能会生成超过一百万的 IP 地址,这可能导致性能问题。", variable_bits_count);std::process::exit(1);}// 计算可能的 IP 地址数量 (2^variable_bits_count)let total_ips = 1u32 << variable_bits_count;// 生成所有可能的 IP 地址let mut matching_ips = Vec::with_capacity(total_ips as usize);for i in 0..total_ips {// 将 i 的位填充到可变位的位置let mut ip = fixed_bits;let mut temp_i = i;// 遍历每个位,将 temp_i 的位填充到可变位for bit in 0..32 {if (variable_mask >> bit) & 1 != 0 {ip |= (temp_i & 1) << bit;temp_i >>= 1;}}matching_ips.push(u32_to_ip(ip));}matching_ips
}#[tauri::command]
fn calculate(ip:String, mask:String)->Result<Vec<Ipv4Addr>, String> {// 解析 IP 地址let ip = match Ipv4Addr::from_str(&ip) {Ok(ip)  => ip,Err(_)  => return Err(format!("无效的 IP 地址: {}", &ip)),};// 解析通配符掩码let wildcard_mask = match Ipv4Addr::from_str(&mask) {Ok(m)   => m,Err(_)  => return Err(format!("无效的通配符掩码: {}", &mask)),};// 计算所有匹配的 IP 地址let matching_ips = calculate_matching_ips(ip, wildcard_mask);Ok(matching_ips)
}

成果展示

http://www.lryc.cn/news/616243.html

相关文章:

  • 【算法题】:和为N的连续正数序列
  • 数学建模:控制预测类问题
  • Python 获取对象信息的所有方法
  • matlab实现随机森林算法
  • Doubletrouble靶机练习
  • 点击速度测试:一款放大操作差距的互动挑战游戏
  • #Datawhale AI夏令营#第三期全球AI攻防挑战赛(AIGC技术-图像方向)
  • 如何用分析方法解决工作中的问题?
  • 检索召回率优化探究五(BGE-M3 混合检索):基于LangChain0.3 集成Milvu2.5 向量数据库构建的智能问答系统
  • Linux系统编程Day11 -- 进程属性和常见进程
  • 学习模板元编程(3)enable_if
  • 【树状数组】Dynamic Range Sum Queries
  • [激光原理与应用-221]:设计 - 皮秒紫外激光器 - 常见技术难题、原因与解决方案
  • Linux-静态配置ip地址
  • 【无标题】命名管道(Named Pipe)是一种在操作系统中用于**进程间通信(IPC)** 的机制
  • 深度解析Linux设备树(DTS):设计原理、实现框架与实例分析
  • 基于Qt/QML 5.14和YOLOv8的工业异常检测Demo:冲压点智能识别
  • 线程池的核心线程数与最大线程数怎么设置
  • 基于FFmpeg的B站视频下载处理
  • 简要介绍交叉编译工具arm-none-eabi、arm-linux-gnueabi与arm-linux-gnueabihf
  • 【iOS】JSONModel源码学习
  • 2025.8.10总结
  • mpv core_thread pipeline
  • 第16届蓝桥杯Scratch选拔赛初级及中级(STEMA)2025年4月13日真题
  • ARM保留的标准中断处理程序入口和外设中断处理程序入口介绍
  • Python设计模式 - 装饰模式
  • 双亲委派机制是什么?
  • 亚麻云之轻云直上EC2
  • 硬件开发_基于STM32单片机的智能电梯系统
  • 关键基础设施中的新兴技术如何扩大网络风险