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

Tauri 跨平台开发指南及实战:用前端技术征服桌面应用(合集-万字长文)

厌倦了笨重的Electron应用?想要构建体积小、性能高、安全可靠的跨平台桌面应用?Tauri将是你的不二之选!本教程带你从入门到精通,掌握这个下一代桌面应用开发框架,并通过实战APK分析工具项目,将理论知识转化为实际应用。无论你是前端开发者还是Rust爱好者,这篇万字长文都将助你快速驾驭Tauri的强大能力!

目录

  • 什么是 Tauri
  • Tauri vs Electron
  • 环境准备
  • 创建首个 Tauri 应用
  • Tauri 架构详解
  • 前后端通信
  • 文件系统访问
  • 安全策略
  • 打包与发布
  • 实战项目:APK 分析工具
  • 性能优化
  • 常见问题与解决方案
  • 扩展资源

什么是 Tauri

Tauri 是一个构建跨平台桌面应用的现代化框架,它允许开发者使用 Web 技术(HTML、CSS、JavaScript/TypeScript)来构建应用的 UI,同时使用 Rust 作为后端来保证性能和安全性。与传统的 Electron 不同,Tauri 应用通常更小、更快、更安全。

Tauri 的核心理念是:

  • 安全优先:精细的权限系统和严格的 CSP(内容安全策略)
  • 性能至上:基于 Rust 构建的高性能后端
  • 资源效率:更小的应用大小和更低的内存占用
  • 隐私保护:默认不收集任何数据

自 Tauri 2.0 起,该框架已经成熟并得到了广泛应用,支持 Windows、macOS 和 Linux 平台,并提供了丰富的 API 和插件生态系统。

Tauri vs Electron

特性TauriElectron
底层架构Rust + 系统 WebViewChromium + Node.js
应用大小小(~3-10MB)大(~120MB+)
内存占用
安全性高(精细权限控制)中等
生态系统增长中成熟
学习曲线陡峭(需要了解 Rust)平缓(纯 JavaScript)
开发体验需要管理前后端接口单一运行时
支持平台Windows, macOS, LinuxWindows, macOS, Linux

环境准备

在开始使用 Tauri 前,需要配置好开发环境:

1. 安装 Rust

# Windows/macOS/Linux
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh# 或在 Windows 上通过安装程序
# 访问 https://www.rust-lang.org/tools/install 下载安装程序

验证安装:

rustc --version
cargo --version

2. 安装系统依赖

Windows

  • 安装 Visual Studio 构建工具
  • 选择"C++ 构建工具"
  • 安装 WebView2

macOS

xcode-select --install

Linux (Ubuntu/Debian)

sudo apt update
sudo apt install libwebkit2gtk-4.0-dev \build-essential \curl \wget \libssl-dev \libgtk-3-dev \libayatana-appindicator3-dev \librsvg2-dev

3. 安装 Node.js 和包管理器

推荐使用 Node.js 16+ 和 pnpm:

# 安装 nvm (Node Version Manager)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash# 安装并使用 Node.js
nvm install 18
nvm use 18# 安装 pnpm
npm install -g pnpm

4. 安装 Tauri CLI

cargo install tauri-cli
# 或
npm install -g @tauri-apps/cli

创建首个 Tauri 应用

使用 Tauri CLI 创建项目

# 交互式创建新项目
pnpm create tauri-app my-app# 按提示选择前端框架和配置
cd my-app

项目结构

my-app/
├── src/                 # 前端代码
│   ├── App.vue          # Vue 主组件
│   └── main.js          # 入口点
├── src-tauri/           # Rust 后端代码
│   ├── src/             # Rust 源码
│   │   └── main.rs      # 程序入口
│   ├── Cargo.toml       # Rust 依赖配置
│   ├── tauri.conf.json  # Tauri 配置
│   └── build.rs         # 构建脚本
└── package.json         # 前端依赖

开发与调试

# 启动开发模式
pnpm run tauri dev# 构建生产版本
pnpm run tauri build

Tauri 架构详解

Tauri 采用前后端分离的架构:

  1. 前端:使用 Web 技术(Vue、React、Svelte 等)构建 UI
  2. 后端:使用 Rust 构建本地功能和系统集成
  3. 核心:WebView 窗口管理和 IPC(进程间通信)系统

关键概念:

  • Window:应用窗口管理
  • Command:暴露给前端的 Rust 函数
  • Event:前后端之间的消息传递系统
  • State:多窗口共享的状态管理
  • Plugin:扩展 Tauri 功能的模块

前后端通信

定义 Rust 命令

src-tauri/src/main.rs 中:

#[tauri::command]
fn hello(name: &str) -> String {format!("Hello, {}!", name)
}fn main() {tauri::Builder::default().invoke_handler(tauri::generate_handler![hello]).run(tauri::generate_context!()).expect("error while running tauri application");
}

从前端调用 Rust 函数

import { invoke } from '@tauri-apps/api/core';// 调用 Rust 命令
async function greet() {const response = await invoke('hello', { name: 'Tauri' });console.log(response); // "Hello, Tauri!"
}

在 Rust 中访问前端状态

#[tauri::command]
async fn save_settings(window: tauri::Window, settings: String) -> Result<(), String> {// 操作窗口window.set_title(&format!("New settings: {}", settings)).map_err(|e| e.to_string())?;// 执行其他操作Ok(())
}

事件系统

Rust 发送事件

#[tauri::command]
fn start_process(window: tauri::Window) -> Result<(), String> {// 启动长时间运行的任务std::thread::spawn(move || {// 执行任务window.emit("process-update", Some(42)).expect("failed to emit event");});Ok(())
}

前端监听事件

import { listen } from '@tauri-apps/api/event';// 监听事件
const unlisten = await listen('process-update', (event) => {console.log('Got update:', event.payload);
});// 停止监听
unlisten();

文件系统访问

Tauri 提供了安全的文件系统访问 API,在 Tauri 2.0 中通过插件提供:

import { writeTextFile, readTextFile } from '@tauri-apps/plugin-fs';// 读取文件
async function readFile() {try {const contents = await readTextFile('example.txt');console.log(contents);} catch (err) {console.error('Failed to read file:', err);}
}// 写入文件
async function writeFile() {try {await writeTextFile('output.txt', 'Hello, Tauri!');console.log('File written successfully');} catch (err) {console.error('Failed to write file:', err);}
}

安全策略

Tauri 实现了多层安全保护:

  1. 权限系统:精细控制应用可以访问的资源

tauri.conf.json 中配置:

{"tauri": {"allowlist": {"fs": {"scope": {"allow": ["$APP/*"],"deny": ["$APP/config.json"]}},"shell": {"execute": false,"sidecar": false,"open": true}}}
}
  1. CSP:内容安全策略控制资源加载
{"tauri": {"security": {"csp": "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'"}}
}
  1. 沙箱隔离:限制应用能力

打包与发布

配置应用信息

src-tauri/tauri.conf.json 中:

{"package": {"productName": "My Tauri App","version": "1.0.0"},"build": {"distDir": "../dist","devPath": "http://localhost:5173","beforeDevCommand": "pnpm dev","beforeBuildCommand": "pnpm build"},"tauri": {"bundle": {"identifier": "com.mycompany.myapp","icon": ["icons/32x32.png","icons/128x128.png","icons/128x128@2x.png"]}}
}

构建生产版本

pnpm run tauri build

构建产物位于 src-tauri/target/release/bundle/,包括:

  • Windows: .exe, .msi
  • macOS: .app, .dmg
  • Linux: .AppImage, .deb, .rpm

自动更新

tauri.conf.json 中配置:

{"tauri": {"updater": {"active": true,"endpoints": ["https://releases.myapp.com/{{target}}/{{current_version}}"],"dialog": true,"pubkey": "YOUR_PUBLIC_KEY"}}
}

实战项目:APK 分析工具

本节将介绍如何使用 Tauri 构建一个实际的 APK 分析工具,与本项目 apkparse-tauri 类似。
项目地址:ApkParse Github

架构设计

APK 分析工具由以下部分组成:

  1. 前端:Vue 3 + TypeScript UI
  2. 后端:Rust 处理 APK 解析
  3. 核心功能:文件解析、权限分析、签名验证

项目创建

# 创建 Tauri + Vue 项目
pnpm create tauri-app apk-analyzer
cd apk-analyzer

Rust 后端实现

src-tauri/src/ 中创建 APK 解析器:

// src-tauri/src/apk_parser.rs
use serde::{Serialize, Deserialize};
use std::path::Path;
use std::io::Read;
use std::fs::File;
use zip::ZipArchive;#[derive(Debug, Serialize, Deserialize)]
pub struct ApkInfo {pub package_name: String,pub version_name: String,pub version_code: String,pub permissions: Vec<String>,
}pub struct ApkParser;impl ApkParser {pub fn parse(path: &Path) -> Result<ApkInfo, String> {// 打开 APK 文件 (实际上是 ZIP 文件)let file = File::open(path).map_err(|e| format!("Failed to open APK: {}", e))?;let mut archive = ZipArchive::new(file).map_err(|e| format!("Invalid APK format: {}", e))?;// 提取 AndroidManifest.xml// 注意:实际实现需要解析二进制 AndroidManifest.xml// 这里简化处理// 模拟解析结果Ok(ApkInfo {package_name: "com.example.app".to_string(),version_name: "1.0.0".to_string(),version_code: "1".to_string(),permissions: vec!["android.permission.INTERNET".to_string(),"android.permission.READ_EXTERNAL_STORAGE".to_string(),],})}
}

定义 Tauri 命令:

// src-tauri/src/commands.rs
use crate::apk_parser::{ApkParser, ApkInfo};
use std::path::Path;#[tauri::command]
pub fn parse_apk(path: String) -> Result<ApkInfo, String> {let path = Path::new(&path);ApkParser::parse(path)
}

注册命令:

// src-tauri/src/main.rs
mod apk_parser;
mod commands;use commands::parse_apk;fn main() {tauri::Builder::default().invoke_handler(tauri::generate_handler![parse_apk]).run(tauri::generate_context!()).expect("error while running tauri application");
}

前端实现

创建上传组件:

<!-- src/components/ApkUploader.vue -->
<template><div class="uploader"@dragover.prevent@drop.prevent="onFileDrop"@click="openFileDialog"><div class="upload-area"><div v-if="!isUploading"><p>拖放 APK 文件或点击选择</p></div><div v-else><p>分析中...</p></div></div></div>
</template><script setup>
import { ref } from 'vue';
import { invoke } from '@tauri-apps/api/tauri';
import { open } from '@tauri-apps/plugin-dialog';const isUploading = ref(false);
const emit = defineEmits(['result']);async function openFileDialog() {try {const selected = await open({multiple: false,filters: [{name: 'APK Files',extensions: ['apk']}]});if (selected) {processApkFile(selected);}} catch (err) {console.error('Failed to open file dialog:', err);}
}async function onFileDrop(e) {const files = e.dataTransfer.files;if (files.length > 0) {const fileInfo = files[0];// 在 Tauri 中,我们需要获取真实路径// 浏览器 API 受限,需要通过 Tauri 路径转换if ('path' in fileInfo) {processApkFile(fileInfo.path);}}
}async function processApkFile(path) {isUploading.value = true;try {// 调用 Rust 命令解析 APKconst result = await invoke('parse_apk', { path });emit('result', result);} catch (err) {console.error('Failed to parse APK:', err);} finally {isUploading.value = false;}
}
</script><style scoped>
.uploader {border: 2px dashed #ccc;border-radius: 8px;padding: 40px;text-align: center;cursor: pointer;transition: all 0.3s ease;
}.uploader:hover {border-color: #4a86e8;background-color: rgba(74, 134, 232, 0.05);
}
</style>

创建结果显示组件:

<!-- src/components/AnalysisResult.vue -->
<template><div v-if="apkInfo" class="result-container"><h2>APK 分析结果</h2><div class="info-section"><h3>基本信息</h3><p><strong>包名:</strong>{{ apkInfo.package_name }}</p><p><strong>版本:</strong>{{ apkInfo.version_name }} ({{ apkInfo.version_code }})</p></div><div class="permissions-section"><h3>权限 ({{ apkInfo.permissions.length }})</h3><ul><li v-for="(perm, index) in apkInfo.permissions" :key="index">{{ formatPermissionName(perm) }}</li></ul></div></div>
</template><script setup>
import { defineProps } from 'vue';const props = defineProps({apkInfo: Object
});function formatPermissionName(permission) {// 简化权限名称显示return permission.split('.').pop() || permission;
}
</script><style scoped>
.result-container {padding: 20px;background: #f9f9f9;border-radius: 8px;margin-top: 20px;
}.info-section, .permissions-section {margin-bottom: 20px;
}h3 {border-bottom: 1px solid #eee;padding-bottom: 8px;
}ul {list-style-type: none;padding: 0;
}li {padding: 6px 0;border-bottom: 1px dashed #eee;
}
</style>

主应用组件:

<!-- src/App.vue -->
<template><div class="container"><h1>APK 分析工具</h1><p class="description">上传 Android APK 文件进行分析</p><ApkUploader @result="handleResult" /><AnalysisResult :apk-info="apkInfo" /></div>
</template><script setup>
import { ref } from 'vue';
import ApkUploader from './components/ApkUploader.vue';
import AnalysisResult from './components/AnalysisResult.vue';const apkInfo = ref(null);function handleResult(result) {apkInfo.value = result;
}
</script><style>
body {font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;margin: 0;padding: 0;background: #fafafa;color: #333;
}.container {max-width: 800px;margin: 0 auto;padding: 40px 20px;
}h1 {text-align: center;margin-bottom: 10px;
}.description {text-align: center;color: #666;margin-bottom: 30px;
}
</style>

实现完整功能

对于完整的 APK 分析工具,还需添加以下功能:

  1. Rust 扩展功能

    • 处理二进制 AndroidManifest.xml
    • 提取签名信息
    • 分析 APK 组件
    • 计算哈希值
  2. UI 增强

    • 添加详细分析页面
    • 实现结果导出功能
    • 添加历史记录
  3. 安全功能

    • 权限风险评估
    • 恶意软件检测集成
    • 证书验证

性能优化

Rust 性能优化

  1. 并行处理:使用 Rust 的并行处理能力
use rayon::prelude::*;fn process_large_dataset(data: &[u8]) -> Vec<u8> {data.par_chunks(1024).map(|chunk| process_chunk(chunk)).collect()
}
  1. 异步命令:避免 UI 冻结
#[tauri::command]
async fn long_task() -> Result<String, String> {// 执行耗时操作tokio::time::sleep(std::time::Duration::from_secs(2)).await;Ok("Done".to_string())
}

前端优化

  1. 虚拟列表:处理大量数据
<template><div class="list-container" ref="container"><divv-for="item in visibleItems":key="item.id":style="{ top: `${item.position}px` }"class="list-item">{{ item.content }}</div></div>
</template><script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';const props = defineProps({items: Array
});const container = ref(null);
const scrollTop = ref(0);
const itemHeight = 50;
const visibleCount = ref(10);onMounted(() => {const el = container.value;if (el) {el.addEventListener('scroll', handleScroll);visibleCount.value = Math.ceil(el.clientHeight / itemHeight) + 2;}
});onUnmounted(() => {const el = container.value;if (el) {el.removeEventListener('scroll', handleScroll);}
});function handleScroll(e) {scrollTop.value = e.target.scrollTop;
}const visibleItems = computed(() => {const start = Math.floor(scrollTop.value / itemHeight);return props.items.slice(start, start + visibleCount.value).map((item, index) => ({...item,position: (start + index) * itemHeight}));
});
</script><style scoped>
.list-container {height: 400px;overflow-y: auto;position: relative;
}.list-item {position: absolute;left: 0;right: 0;height: 50px;
}
</style>
  1. 懒加载组件:减少初始加载时间
import { defineAsyncComponent } from 'vue';const HeavyComponent = defineAsyncComponent(() => import('./components/HeavyComponent.vue')
);
  1. Web Workers:移除主线程阻塞
// worker.js
self.onmessage = (e) => {const result = heavyComputation(e.data);self.postMessage(result);
};function heavyComputation(data) {// 执行耗时计算return processedData;
}// 使用 Worker
const worker = new Worker('worker.js');
worker.onmessage = (e) => {console.log('Result from worker:', e.data);
};
worker.postMessage(data);

常见问题与解决方案

1. 路径问题

问题:跨平台路径不一致

解决方案:使用 Tauri 的路径 API

import { appConfigDir, join } from '@tauri-apps/api/path';async function getConfigPath() {const configDir = await appConfigDir();return await join(configDir, 'config.json');
}

2. 窗口管理

问题:创建和管理多窗口

解决方案

import { WebviewWindow } from '@tauri-apps/api/window';// 创建窗口
const webview = new WebviewWindow('settings', {url: 'settings.html',title: '设置',width: 800,height: 600
});// 监听窗口事件
webview.once('tauri://created', () => {console.log('Settings window created');
});webview.once('tauri://error', (e) => {console.error('Settings window error:', e);
});

3. 状态共享

问题:不同窗口间状态共享

解决方案:使用 Rust 状态管理

// 定义全局状态
struct AppState {config: Mutex<Config>,
}// 在 main.rs 中管理状态
fn main() {let state = AppState {config: Mutex::new(Config::default()),};tauri::Builder::default().manage(state).invoke_handler(tauri::generate_handler![get_config, update_config]).run(tauri::generate_context!()).expect("error while running tauri application");
}// 在命令中访问状态
#[tauri::command]
fn get_config(state: tauri::State<AppState>) -> Result<Config, String> {let config = state.config.lock().map_err(|e| e.to_string())?;Ok(config.clone())
}#[tauri::command]
fn update_config(state: tauri::State<AppState>, new_config: Config) -> Result<(), String> {let mut config = state.config.lock().map_err(|e| e.to_string())?;*config = new_config;Ok(())
}

扩展资源

  • Tauri 官方文档
  • Rust 编程语言
  • Tauri GitHub 仓库
  • Awesome Tauri
  • Tauri Discord 社区

本教程通过理论讲解和实战示例介绍了 Tauri 框架,从基础概念到构建实际应用。随着生态系统的不断发展,Tauri 正成为构建高性能、安全且体积小的桌面应用程序的首选工具之一。

通过跟随本教程中的实战部分,你已经了解了如何构建一个基本的 APK 分析工具。要了解更多复杂功能的实现,可以参考本项目的完整源代码,该项目展示了更多高级特性和最佳实践。

相关文章:

Tauri 跨平台开发指南及实战:用前端技术征服桌面应用(合集-万字长文)

厌倦了笨重的Electron应用&#xff1f;想要构建体积小、性能高、安全可靠的跨平台桌面应用&#xff1f;Tauri将是你的不二之选&#xff01;本教程带你从入门到精通&#xff0c;掌握这个下一代桌面应用开发框架&#xff0c;并通过实战APK分析工具项目&#xff0c;将理论知识转化…...

深入解析 Linux 进程池:原理、实现与高并发优化

引言 当你的服务器需要同时处理 10,000 个客户端请求时&#xff0c;传统的"来一个请求创建一个进程"模式会导致严重的性能瓶颈。此时&#xff0c;进程池&#xff08;Process Pool&#xff09; 便成为关键解决方案。它像一支训练有素的特种部队&#xff0c;通过预先创…...

[Python]非零基础的快速上手

从js转的python&#xff0c;没有从初学者阶段开始&#xff0c;主打一个快速上手能写再说. pycharm:一种编辑器 数据类型 基本数据类型:整型(整数)、浮点型、字符型、布尔型 复杂数据类型:列表(数组)、集合区{1,2,3}、元组(1,3.4)字典{n’:2,b:1} 模板字符串 输出模板字符串…...

《算法笔记》10.5小节——图算法专题->最小生成树 问题 E: Jungle Roads

题目描述 The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid money was spent on extra roads between villages some years ago. But the jungle overtakes roads relentlessly, so the large road network is too expensive to mai…...

数据中心网络架构:高效规划与自动化设计实践

在数据中心网络架构规划设计中&#xff0c;面临如下难点&#xff1a; 设备数量庞大&#xff1a; 服务器、交换机等设备数量多&#xff0c;如何合理规划机柜布局和空间分配&#xff0c;避免资源浪费或密度超标&#xff0c;成为设计难点。 线缆设计复杂&#xff1a; 海量线缆…...

Mysql存储引擎、锁机制

Mysql存储引擎 InnoDB​&#xff08;MySQL 5.5 及以后版本中的默认存储引擎&#xff09; ​​事务支持​​&#xff1a;支持 ​​ACID 事务​​&#xff0c;适合需要高可靠性的场景&#xff08;如支付、订单&#xff09;。 ​​锁机制​​&#xff1a;默认使用 ​​行级锁​​…...

UVA1537 Picnic Planning

目录 题目算法标签: 最小生成树, k r u s k a l kruskal kruskal重构树, 树形 d p dp dp思路重构树代码 题目 UVA1537 Picnic Planning 算法标签: 最小生成树, k r u s k a l kruskal kruskal重构树, 树形 d p dp dp 思路 将 1 1 1号点设置为终点, 然后执行重构树计算度数…...

通过AWS Console连接服务器,简化运维过程

简单通过AWS Console连接您的Linux服务器 本文作者: 封磊 Eclicktech SA | AWS Community Builder DevTool | AWS UGL | 亚马逊云科技云博主 阿里云&InfoQ&CSDN签约作者 文章目录 简单通过AWS Console连接您的Linux服务器本文作者: 封磊Eclicktech SA | AWS Community …...

公交实时查询小程序功能点开发

线路查询&#xff1a;用户可输入公交线路号码&#xff0c;小程序实时显示该线路车辆位置与发车信息&#xff0c;能一键切换行驶方向&#xff0c;助用户依实时情况选合适候车站点。站点查询&#xff1a;输入车站信息&#xff0c;小程序呈现经过该站所有公交线路及公交信息&#…...

nginx配置集群服务器中的tcp负载均衡器

文章目录 前言1. Ubuntu下nginx安装2. nginx的tcp负载配置 前言 假设一台机器支持两万的并发量&#xff0c;现在我们需要保证八万的并发量。首先想到的是升级服务器的配置&#xff0c;比如提高 CPU 执行频率&#xff0c;加大内存等提高机器的物理性能来解决此问题。但是单台机…...

Qt/C++开发监控GB28181系统/获取设备信息/设备配置参数/通道信息/设备状态

一、前言 设备注册成功后&#xff0c;接下来要做的就是获取设备的信息&#xff0c;尤其是通道信息&#xff0c;根据国标协议&#xff0c;永远只有两个层级&#xff0c;一个是设备&#xff0c;然后就是设备下面多个通道&#xff0c;设备编码在整个系统中唯一&#xff0c;通道编…...

Linux系统基础:基础指令简介(网络概念部分)

简介&#xff1a;Linux 是一种开源的类 Unix 操作系统内核&#xff0c;由 Linus Torvalds 于 1991 年首次发布。经过多年发展&#xff0c;它已成为服务器、嵌入式设备和个人计算机领域的重要操作系统。 网络基础概念 初始协议 简单来说&#xff0c;协议是一种约定&#xff0…...

labview项目文件架构

为了使 LabVIEW 项目更具可扩展性和易于维护&#xff0c;合理规划和设计项目文件结构是非常重要的。 以下是一些基于行业经验和最佳实践的建议&#xff1a; 1. ### 文件夹层次划分 将不同的功能模块分开存储在一个清晰的分层目录结构中是一个常见的做法。通常情况下&#xff…...

nuxt项目中引入并配置 iview

安装iview npm install iview --save注&#xff1a;想要加入其它的配置&#xff0c;可以在 nuxt.config.js 的 plugins 配置项中加入&#xff0c;同时在 plugins 文件夹下加入引入逻辑。 在nuxt.config.js文件中写&#xff1a; {src: ~plugins/iview, ssr: true}同时新建 plugi…...

Origin绘图操作:点线图符号显示不全解决方法

一、问题说明 在用origin绘制点线图时&#xff0c;图表刻度线处的点符号显示不完全&#xff0c;如图所示&#xff1a; 二、解决方法 方法一&#xff1a;调整坐标轴刻度&#xff0c;使其能够显示全部数据点。 方法二&#xff1a;有时为了图表美观&#xff0c;则不对坐标轴刻…...

【进程与线程】

文章目录 一、实验目的二、实验内容与设计思想实验内容设计思路 三、实验代码实现四、总结 一、实验目的 1.深刻理解进程和线程的概念&#xff0c;掌握线程与进程在组成成分上的差别&#xff1b; 2.进一步认识并发执行的实质。 二、实验内容与设计思想 实验内容 用pipe()创…...

项目实战-飞机大战【补档】

和项目实战-贪吃蛇大作战【补档】-CSDN博客一样&#xff0c;这也是一个我在大一和网友完成的项目的补档。Dont waste your youth—time flies. 目录 1.工具&环境 2.项目简介 3.需求文档 4.流程图 5.产品原型图 6.可行性分析 7.源代码 8.实战效果 ​编辑 9.心得…...

算法基础学习|02归并排序——分治

一、思路 &#xff08;1&#xff09;确定分界点&#xff1a;mid(lr)/2 ——这里和快排不同 &#xff08;2&#xff09;递归排序&#xff08;left right&#xff09; &#xff08;3&#xff09;归并——合二为一 时间复杂度nlogn 二、题目练习 三、模板 归并排序 …...

测试基础笔记第十六天

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、UI自动化介绍1.认识UI自动化测试2.实施UI自动化测试前置条件3.UI自动化测试执行时机4.UI自动化测试核心作用和劣势 二、认识Web自动化测试工具-Selenium021.Sel…...

Android项目中使用ComposeUI

首先确认项目环境kotlin版本&#xff0c;以下是本机的版本 使用命令 ./gradlew -version 这里kotlin 版本是1.5.31 然后查看build.gradle sdk版本 这里是32 属于低版本 然后需要添加以下配置 buildFeatures {compose true}composeOptions {kotlinCompilerExtensionVersio…...

springboot中有关数据库信息转换的处理

现代项目一般都是前后端分离的&#xff0c;前端只负责展示数据&#xff0c;不负责对数据处理&#xff0c;所以所有数据处理工作都由后端进行 比如在仿京东中的status&#xff0c;审核信息展示&#xff0c;数据库中是以0/1显示&#xff0c;但是前端需要以"审核/未审核&quo…...

HHsuite同源序列搜索数据库构建

HHsuite 可用的数据库格式简介 HHsuite 是用于蛋白质序列比对和同源性检测的工具套件,它使用特定的数据库格式以实现高效的数据存储和快速的检索。HHsuite 常用的数据库格式主要基于 FFINDEX(Flat-File Index),这是一种简单而高效的文件索引系统,它将数据文件(如蛋白质序…...

大模型推理:Qwen3 32B vLLM Docker本地部署

Qwen3基础知识 此次Qwen3开源8个模型&#xff08;MOE架构&#xff1a;Qwen3-235B-A22B、Qwen3-30B-A3B&#xff0c;Dense架构&#xff1a;Qwen3 0.6B/1.7B/4B/8B/14B/32B&#xff09;&#xff0c;新版本的Qwen3特性包括&#xff1a; 支持混合思维模式&#xff0c;即推理/非推…...

第十六届蓝桥杯 2025 C/C++B组 第二轮省赛 全部题解(未完结)

目录 前言&#xff1a; 试题A&#xff1a;密密摆放 试题B&#xff1a;脉冲强度之和 试题C&#xff1a;25之和 试题D&#xff1a;旗帜 试题H&#xff1a;破解信息 前言&#xff1a; 这是我后续刷到的第二轮省赛的题目&#xff0c;我自己也做了一下&#xff0c;和第一轮省赛…...

域名转移:什么是转移码/EPP码/授权码?

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…...

Android 系统发展史

Android 1.0&#xff1a;2008年9月 全球第一台安卓设备是 HTC Dream Google地图、YouTube、HTML浏览器、Gmail、即使消息、短信、彩信、日历等 Android Market&#xff08;应用程序商店&#xff09; Android 1.1&#xff1a;2009年2月&#xff08;Petit Four 花色小蛋糕&am…...

Python中的defaultdict方法

文章目录 核心特点基本语法常见使用场景1. 分组数据&#xff08;默认值为列表&#xff09;2. 计数&#xff08;默认值为整数&#xff09;3. 集合操作&#xff08;默认值为集合&#xff09;4. 嵌套字典 注意事项与普通字典对比总结1. 键&#xff08;Key&#xff09;的类型2. 值&…...

Android启动应用时屏蔽RecyclerView滑动,延时后再允许滑动,Kotlin

Android启动应用时屏蔽RecyclerView滑动&#xff0c;延时后再允许滑动&#xff0c;Kotlin var bCanScrollVertically falselifecycleScope.launch(Dispatchers.Default) {repeatOnLifecycle(Lifecycle.State.CREATED) {Log.d(TAG, "Lifecycle.State.CREATED")delay(…...

2025运维工程师面试题1(答案在后一张)

一、逻辑思维能力考核&#xff1a; 问题1&#xff1a; 3个人去投宿&#xff0c;一晚30元三个人每人掏了10元凑够30元交给了老板后来老板说今天优惠只要25元就够了&#xff0c;拿出5元命令服务生退还给他们&#xff0c;服务生偷偷藏起了2元&#xff0c;然后&#xff0c;把剩下…...

在网页中使用【LaTeX 数学公式块】的完整步骤总结

以下是在网页中使用 LaTeX 数学公式块的完整步骤总结&#xff0c;记录如何让网页正确渲染 LaTeX 数学表达式&#xff08;如 \(H(X) -\sum p(x) \log p(x)\) 这样的公式&#xff09;&#xff1a; ✅ 使用 LaTeX 数学公式块的完整步骤&#xff08;以 KaTeX 为例&#xff09; &am…...

新人销售如何找精准客户?

深入了解自身产品或服务。 清晰掌握产品优势、应用场景和解决的问题&#xff0c;比如销售办公软件&#xff0c;要熟知其提升办公效率的具体功能&#xff0c;以此定位需求客户。 利用社交媒体平台。 像领英可完善资料&#xff0c;加入行业群组分享内容吸引潜在客户&#xff1…...

【Unity】使用Socket建立客户端和服务端并进行通信的例子

Socket服务端: using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class SocketServer { public static Socket listenSocket;//监听Socket public static List<Socket>…...

为什么要学习《易经》?

《易经》精华解读&#xff1a;变易之道与人生智慧 《易经》&#xff08;《周易》&#xff09;是中国最古老的经典之一&#xff0c;被誉为“群经之首&#xff0c;大道之源”。它不仅是占卜之书&#xff0c;更是一部哲学经典&#xff0c;揭示了宇宙运行的规律和人生处世的智慧。…...

13.继承、重载、重写、多态、抽象类、接口、final、Static的学习

一、继承 继承&#xff1a;你继承谁你就是谁&#xff0c;继承是一种严格的父子关系 &#xff08;在父类里面抽取的属性和方法一定是所有子类所共有&#xff09; &#xff08;Student继承Person&#xff0c;那么Student就是人&#xff09; UML: 类图&#xff08;描述类和类之间的…...

SpringBoot Actuator未授权访问漏洞的全面解析与解决方案

引言 SpringBoot Actuator 作为应用监控与管理的核心组件,为开发者提供了丰富的系统自省和运维能力。然而,其默认配置中可能存在的未授权访问漏洞,已成为企业安全防护的潜在风险。本文将从漏洞原理、影响范围、检测方法到解决方案,系统性地剖析该问题,并提供覆盖开发、运维…...

使用C# ASP.NET创建一个可以由服务端推送信息至客户端的WEB应用(1)

背景 用户在WEB页面上点击按钮&#xff0c;服务端需要执行一系列操作&#xff0c;该操作系列步骤较多且耗时长&#xff0c;为了更好的给用户浏览体验&#xff0c;需要在每进行一个步骤由服务端推送消息给客户端&#xff08;浏览器&#xff09;&#xff0c;避免一个长时间的操作…...

一网统管建设组织保障分工常见表

在 “一网统管” 建设进程中,强有力的组织保障体系与各业务部门间的紧密分工协作是确保建设成效的关键。 从组织保障层面来看,需建立专门的 “一网统管” 建设领导小组,由政府高层领导担任组长,各关键业务部门负责人作为组员,以此强化对整体建设工作的统筹规划与组…...

JVM | CMS垃圾收集器详解

目录 CMS垃圾回收器简介 为什么CMS图中初始标记的阶段是单线程&#xff1f;为啥不多线程&#xff1f;当然现在默认多线程了。 CMS的两种模式与一种特殊策略 Backgroud CMS 记忆集 卡表 ForeGroud CMS CMS的标记压缩算法 三色标记 &#xff08;便于理解而被后人提出&am…...

android开发中的多线程、数据存储同步功能实现方案和应用场景

在Android开发中&#xff0c;多线程、数据存储与同步功能有多种实现方案&#xff0c;以下是详细介绍及其应用场景&#xff1a; 多线程 实现方案&#xff1a; Thread类与Runnable接口&#xff1a;通过继承Thread类并重写run方法&#xff0c;或实现Runnable接口并将其传入Threa…...

【C++初阶】--- 模板进阶

1.非类型模板参数 • 模板参数分类类型形参与非类型形参。 • 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 • 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将该参…...

数据库所有知识

# 第一章 数据库-理论基础 ## 1.1 什么是数据库 数据&#xff1a; 描述事物的符号记录&#xff0c; 可以是数字、 文字、图形、图像、声音、语言等&#xff0c;数据有多种形式&#xff0c;它们都可以经过数字化后存入计算机。 数据库&#xff1a; 存储数据的仓库&#xff0c…...

docker部署的Nextcloud,处于维护模式,如何解决

Nextcloud 在升级后卡在维护模式&#xff0c;以下是针对 Docker 部署的解决方案&#xff1a; 1. 通过 OCC 命令强制关闭维护模式 进入 Nextcloud 容器内部执行命令&#xff1a; # 替换 nextcloud 为你的容器名称 docker exec -it --user www-data nextcloud php occ maintena…...

mongoose插入文档,字段类型, 字段验证, 删除文档,更新文档,读取文档,查询文档的条件控制 ,字段筛选,数据排序,数据截取

、Mongoose 中与 文档操作&#xff08;插入、查询、更新、删除&#xff09;及其相关功能&#xff08;字段类型、验证、条件筛选、排序、分页等&#xff09;相关示例&#xff1a; &#x1f4cb; 一、字段类型定义&#xff08;Schema Types&#xff09; const mongoose require…...

源码编译安装LAMP

一&#xff1a;LAMP概述 LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词&#xff0c;具体包括Linux操作系统、Apache网站服务器、MySQL数据库服务器、PHP…...

C++每日训练 Day 18:构建响应式表单与数据验证(初学者友好)

&#x1f4d8; 本篇目标&#xff1a;在前几日协程与事件驱动机制基础上&#xff0c;构建一个响应式表单系统&#xff0c;实现用户输入的异步验证与反馈。通过协程挂起/恢复机制&#xff0c;简化异步逻辑&#xff0c;提升代码可读性。 &#x1f501; 回顾 Day 17&#xff1a;响应…...

Linux环境变量以及进程虚拟地址原理

目录 一、介绍进程优先级 1.什么是优先级 2.为什么会有优先级 3.Linux中的优先级是怎么确定的 1&#xff09;查看Linux中的优先级 2&#xff09;计算优先级和更改优先级 二、环境变量 1.什么是环境变量 2.环境变量有什么作用 3.环境变量怎么做到的 1&#xff09;查看系统已有的…...

基于非递归求解的汉诺塔超级计算机堆栈与数据区设计方案

基于非递归求解的汉诺塔超级计算机堆栈与数据区设计方案 一、设计背景与目标 汉诺塔问题存在非递归直接求解方法&#xff0c;相较于递归法具有明确移动规律和潜在性能优势。本设计旨在利用非递归求解规律&#xff0c;优化汉诺塔超级计算机的堆栈与数据区结构&#xff0c;降低…...

【Linux应用】在PC的Linux环境下通过chroot运行ARM虚拟机镜像img文件(需要依赖qemu-aarch64、不需要重新安装iso)

【Linux应用】在PC的Linux环境下通过chroot运行ARM虚拟机镜像img文件&#xff08;需要依赖qemu-aarch64、不需要重新安装iso&#xff09; qemu提供了运行ARM虚拟机的方法 具体的操作方式就是建立一个硬盘img 然后通过iso安装到img 最后再运行img即可 这种方式教程很多 很简单 …...

CISC与RISC详解:定义、区别及典型处理器

一、CISC&#xff08;复杂指令集计算机&#xff09; Complex Instruction Set Computer 核心思想&#xff1a;通过设计复杂的指令&#xff0c;减少程序指令数量&#xff0c;以硬件复杂度换取编程便利性。 主要特点&#xff1a; 指令复杂度高&#xff1a; 单条指令可完成多步操…...

数据库中DDL、DML、DCL的区别是什么?

数据库中DDL、DML、DCL的区别是什么&#xff1f; 在数据库的使用过程中&#xff0c;SQL&#xff08;结构化查询语言&#xff09;常常被用来执行不同的操作&#xff0c;主要分为三类&#xff1a;DDL&#xff08;数据定义语言&#xff09;、DML&#xff08;数据操纵语言&#xf…...