Rust异步编程实战:构建高性能WebSocket服务

Rust异步编程实战:构建高性能WebSocket服务

Rust异步编程实战:构建高性能WebSocket服务

在这里插入图片描述

一、WebSocket协议概述

1.1 WebSocket的基本概念

💡WebSocket是一种在单个TCP连接上进行全双工通信的协议,它允许服务器主动向客户端发送消息,而不需要客户端先发起请求。这种通信方式适用于实时应用,如聊天应用、实时通知、在线游戏等。

WebSocket协议的主要特点:

  • 全双工通信:服务器和客户端可以同时发送和接收消息。
  • 低延迟:WebSocket通信的延迟比HTTP低,因为它不需要每次请求都建立新的连接。
  • 可靠性:WebSocket使用TCP协议,保证了消息的可靠传输。
  • 跨域支持:WebSocket支持跨域请求,只需要在服务器端设置相应的CORS策略。

1.2 WebSocket与HTTP的区别

特性HTTPWebSocket
通信方式客户端发起请求,服务器响应全双工通信,服务器可以主动发送消息
连接类型无状态,每次请求建立新连接持久连接,连接建立后保持打开状态
延迟高,因为每次请求需要建立连接低,连接建立后直接通信
适用场景静态资源请求、RESTful API实时应用,如聊天、通知、游戏等

1.3 WebSocket协议的工作原理

  1. 握手阶段:客户端向服务器发送HTTP请求,请求升级协议为WebSocket。
  2. 连接建立:服务器响应升级请求,WebSocket连接建立成功。
  3. 数据传输:服务器和客户端可以通过WebSocket连接发送和接收消息。
  4. 连接关闭:服务器或客户端发送关闭帧,连接关闭。

二、异步WebSocket服务端开发

2.1 使用Axum实现WebSocket服务端

Axum是Rust社区中常用的异步HTTP框架,它提供了简单易用的API来实现WebSocket服务端。

在Cargo.toml中添加依赖:

[dependencies] axum = { version = "0.5", features = ["ws"] } tokio = { version = "1.0", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } 

实现WebSocket服务端:

useaxum::{routing::get,extract::ws::{WebSocket,Message,WebSocketUpgrade},response::IntoResponse,Router,};usetracing_subscriber::prelude::*;usetracing::info;asyncfnws_handler(ws:WebSocketUpgrade)->implIntoResponse{info!("New WebSocket connection"); ws.on_upgrade(|socket|handle_socket(socket))}asyncfnhandle_socket(mut socket:WebSocket){// 发送欢迎消息ifletErr(e)= socket.send(Message::Text("Welcome to WebSocket server".to_string())).await{info!("Error sending welcome message: {}", e);return;}whileletSome(msg)= socket.recv().await{match msg {Ok(msg)=>{match msg {Message::Text(text)=>{info!("Received message: {}", text);// 回复消息let reply =format!("You said: {}", text);ifletErr(e)= socket.send(Message::Text(reply)).await{info!("Error sending message: {}", e);break;}}Message::Binary(data)=>{info!("Received binary message ({} bytes)", data.len());}Message::Ping(data)=>{info!("Received ping");ifletErr(e)= socket.send(Message::Pong(data)).await{info!("Error sending pong: {}", e);break;}}Message::Pong(_)=>{info!("Received pong");}Message::Close(_)=>{info!("Connection closed");break;}}}Err(e)=>{info!("Error receiving message: {}", e);break;}}}info!("WebSocket connection closed");}#[tokio::main]asyncfnmain(){// 初始化日志tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::new("info")).with(tracing_subscriber::fmt::layer()).init();// 创建路由let app =Router::new().route("/ws",get(ws_handler));// 启动服务器let listener =tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();info!("WebSocket server running on http://0.0.0.0:3000");axum::serve(listener, app).await.unwrap();}

2.2 连接管理与消息广播

在实际应用中,我们需要管理多个WebSocket连接,并支持消息广播。我们可以使用tokio::sync::broadcast通道来实现消息广播。

useaxum::{routing::get,extract::ws::{WebSocket,Message,WebSocketUpgrade},response::IntoResponse,Router,};usetracing_subscriber::prelude::*;usetracing::info;usetokio::sync::broadcast;asyncfnws_handler(ws:WebSocketUpgrade, tx:broadcast::Sender<String>)->implIntoResponse{info!("New WebSocket connection");let rx = tx.subscribe(); ws.on_upgrade(|socket|handle_socket(socket, tx, rx))}asyncfnhandle_socket(mut socket:WebSocket, tx:broadcast::Sender<String>,mut rx:broadcast::Receiver<String>,){// 发送欢迎消息ifletErr(e)= socket.send(Message::Text("Welcome to WebSocket server".to_string())).await{info!("Error sending welcome message: {}", e);return;}tokio::spawn(asyncmove{whileletOk(msg)= rx.recv().await{ifletErr(e)= socket.send(Message::Text(msg)).await{info!("Error sending broadcast message: {}", e);break;}}});whileletSome(msg)= socket.recv().await{match msg {Ok(msg)=>{match msg {Message::Text(text)=>{info!("Received message: {}", text);// 广播消息ifletErr(e)= tx.send(text){info!("Error broadcasting message: {}", e);break;}}Message::Binary(data)=>{info!("Received binary message ({} bytes)", data.len());}Message::Ping(data)=>{info!("Received ping");ifletErr(e)= socket.send(Message::Pong(data)).await{info!("Error sending pong: {}", e);break;}}Message::Pong(_)=>{info!("Received pong");}Message::Close(_)=>{info!("Connection closed");break;}}}Err(e)=>{info!("Error receiving message: {}", e);break;}}}info!("WebSocket connection closed");}#[tokio::main]asyncfnmain(){// 初始化日志tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::new("info")).with(tracing_subscriber::fmt::layer()).init();// 创建广播通道let(tx, _)=broadcast::channel(100);// 创建路由let app =Router::new().route("/ws",get(ws_handler)).with_state(tx);// 启动服务器let listener =tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();info!("WebSocket server running on http://0.0.0.0:3000");axum::serve(listener, app).await.unwrap();}

2.3 心跳检测与连接超时

为了确保WebSocket连接的有效性,我们需要实现心跳检测与连接超时机制。

useaxum::{routing::get,extract::ws::{WebSocket,Message,WebSocketUpgrade},response::IntoResponse,Router,};usetracing_subscriber::prelude::*;usetracing::info;usetokio::sync::broadcast;usetokio::time::{interval,Duration};asyncfnws_handler(ws:WebSocketUpgrade, tx:broadcast::Sender<String>)->implIntoResponse{info!("New WebSocket connection");let rx = tx.subscribe(); ws.on_upgrade(|socket|handle_socket(socket, tx, rx))}asyncfnhandle_socket(mut socket:WebSocket, tx:broadcast::Sender<String>,mut rx:broadcast::Receiver<String>,){// 发送欢迎消息ifletErr(e)= socket.send(Message::Text("Welcome to WebSocket server".to_string())).await{info!("Error sending welcome message: {}", e);return;}// 心跳检测letmut heartbeat_interval =interval(Duration::from_secs(10));// 广播接收任务let broadcast_task =tokio::spawn(asyncmove{whileletOk(msg)= rx.recv().await{ifletErr(e)= socket.send(Message::Text(msg)).await{info!("Error sending broadcast message: {}", e);break;}}});// 消息处理任务let message_task =tokio::spawn(asyncmove{whileletSome(msg)= socket.recv().await{match msg {Ok(msg)=>{match msg {Message::Text(text)=>{info!("Received message: {}", text);ifletErr(e)= tx.send(text){info!("Error broadcasting message: {}", e);break;}}Message::Binary(data)=>{info!("Received binary message ({} bytes)", data.len());}Message::Ping(data)=>{info!("Received ping");ifletErr(e)= socket.send(Message::Pong(data)).await{info!("Error sending pong: {}", e);break;}}Message::Pong(_)=>{info!("Received pong");}Message::Close(_)=>{info!("Connection closed");break;}}}Err(e)=>{info!("Error receiving message: {}", e);break;}}}});// 心跳检测任务let heartbeat_task =tokio::spawn(asyncmove{loop{tokio::select!{ _ = heartbeat_interval.tick()=>{ifletErr(e)= socket.send(Message::Ping(vec![])).await{info!("Error sending ping: {}", e);break;}} _ = message_task =>{break;} _ = broadcast_task =>{break;}}}});// 等待所有任务完成let _ =tokio::try_join!(heartbeat_task, message_task, broadcast_task);info!("WebSocket connection closed");}#[tokio::main]asyncfnmain(){tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::new("info")).with(tracing_subscriber::fmt::layer()).init();let(tx, _)=broadcast::channel(100);let app =Router::new().route("/ws",get(ws_handler)).with_state(tx);let listener =tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();info!("WebSocket server running on http://0.0.0.0:3000");axum::serve(listener, app).await.unwrap();}

三、异步WebSocket客户端开发

3.1 使用Tungstenite实现WebSocket客户端

Tungstenite是Rust社区中常用的WebSocket客户端库,它提供了异步和同步两种API。

在Cargo.toml中添加依赖:

[dependencies] tungstenite = "0.18" tokio = { version = "1.0", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } 

实现WebSocket客户端:

usetungstenite::connect;usetungstenite::Message;useurl::Url;usetracing_subscriber::prelude::*;usetracing::info;#[tokio::main]asyncfnmain(){tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::new("info")).with(tracing_subscriber::fmt::layer()).init();info!("Connecting to WebSocket server");let(mut socket, response)=connect(Url::parse("ws://127.0.0.1:3000/ws").unwrap()).unwrap();info!("Connected to WebSocket server, response: {:?}", response);// 发送消息 socket.write_message(Message::Text("Hello, WebSocket!".to_string())).unwrap();// 接收消息loop{match socket.read_message(){Ok(msg)=>{match msg {Message::Text(text)=>{info!("Received message: {}", text);}Message::Binary(data)=>{info!("Received binary message ({} bytes)", data.len());}Message::Ping(data)=>{info!("Received ping"); socket.write_message(Message::Pong(data)).unwrap();}Message::Pong(_)=>{info!("Received pong");}Message::Close(_)=>{info!("Connection closed");break;}}}Err(e)=>{info!("Error receiving message: {}", e);break;}}}info!("Client disconnected");}

3.2 异步WebSocket客户端

Tungstenite也提供了异步API,我们可以使用Tokio的异步运行时来实现异步WebSocket客户端。

usetokio_tungstenite::connect_async;usetungstenite::protocol::Message;useurl::Url;usetracing_subscriber::prelude::*;usetracing::info;#[tokio::main]asyncfnmain(){tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::new("info")).with(tracing_subscriber::fmt::layer()).init();info!("Connecting to WebSocket server");let(ws_stream, response)=connect_async(Url::parse("ws://127.0.0.1:3000/ws").unwrap()).await.unwrap();info!("Connected to WebSocket server, response: {:?}", response);let(mut write,mut read)= ws_stream.split();// 发送消息任务tokio::spawn(asyncmove{ write.send(Message::Text("Hello, WebSocket!".to_string())).await.unwrap();tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; write.send(Message::Text("Another message".to_string())).await.unwrap();tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; write.send(Message::Close(None)).await.unwrap();});// 接收消息任务whileletSome(msg)= read.next().await{match msg {Ok(msg)=>{match msg {Message::Text(text)=>{info!("Received message: {}", text);}Message::Binary(data)=>{info!("Received binary message ({} bytes)", data.len());}Message::Ping(data)=>{info!("Received ping"); write.send(Message::Pong(data)).await.unwrap();}Message::Pong(_)=>{info!("Received pong");}Message::Close(_)=>{info!("Connection closed");break;}}}Err(e)=>{info!("Error receiving message: {}", e);break;}}}info!("Client disconnected");}

3.3 重连机制

在实际应用中,WebSocket连接可能会由于网络问题而断开,我们需要实现重连机制。

usetokio_tungstenite::connect_async;usetungstenite::protocol::Message;useurl::Url;usetracing_subscriber::prelude::*;usetracing::info;usetokio::time::{sleep,Duration};asyncfnconnect_and_handle()->Result<(),Box<dynstd::error::Error>>{info!("Connecting to WebSocket server");let(ws_stream, response)=connect_async(Url::parse("ws://127.0.0.1:3000/ws").unwrap()).await?;info!("Connected to WebSocket server, response: {:?}", response);let(mut write,mut read)= ws_stream.split();// 发送消息任务tokio::spawn(asyncmove{ write.send(Message::Text("Hello, WebSocket!".to_string())).await.unwrap();loop{tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; write.send(Message::Text("Ping".to_string())).await.unwrap();}});// 接收消息任务whileletSome(msg)= read.next().await{match msg {Ok(msg)=>{match msg {Message::Text(text)=>{info!("Received message: {}", text);}Message::Binary(data)=>{info!("Received binary message ({} bytes)", data.len());}Message::Ping(data)=>{info!("Received ping"); write.send(Message::Pong(data)).await.unwrap();}Message::Pong(_)=>{info!("Received pong");}Message::Close(_)=>{info!("Connection closed");break;}}}Err(e)=>{info!("Error receiving message: {}", e);break;}}}info!("Client disconnected");Ok(())}#[tokio::main]asyncfnmain(){tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::new("info")).with(tracing_subscriber::fmt::layer()).init();loop{ifletErr(e)=connect_and_handle().await{info!("Connection error: {}, retrying in 5 seconds", e);sleep(Duration::from_secs(5)).await;}}}

四、实战项目:构建实时聊天应用

4.1 项目需求与架构设计

我们将构建一个简单的实时聊天应用,支持以下功能:

  • 多用户同时聊天
  • 消息广播
  • 用户加入/离开通知
  • 心跳检测
  • 连接超时

项目架构设计:

  • 使用Axum作为WebSocket服务端
  • 使用tokio::sync::broadcast实现消息广播
  • 使用tokio::sync::Mutex管理用户信息
  • 使用HTML和JavaScript实现客户端界面

4.2 服务端实现

创建src/main.rs:

useaxum::{routing::{get, post},extract::{ws::{WebSocket,Message,WebSocketUpgrade},State},response::{IntoResponse,Html},Router,};usetracing_subscriber::prelude::*;usetracing::info;usetokio::sync::{broadcast,Mutex};usetokio::time::{interval,Duration};usestd::collections::HashMap;usestd::sync::Arc;#[derive(Debug, Clone)]structUser{ id:String, name:String,}typeUsers=Arc<Mutex<HashMap<String,User>>>;asyncfnindex()->Html<&'staticstr>{Html(r#" <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Real-Time Chat</title> <style> body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f5f5f5; } .container { max-width: 800px; margin: 0 auto; padding: 20px; } h1 { color: #333; text-align: center; } #chat { height: 400px; overflow-y: scroll; border: 1px solid #ddd; padding: 10px; margin-bottom: 10px; background-color: white; } .message { margin-bottom: 10px; padding: 10px; background-color: #f0f0f0; border-radius: 5px; } .system { color: #666; font-style: italic; } .user { font-weight: bold; } #message-input { width: 80%; padding: 10px; font-size: 14px; } #send-btn { padding: 10px 20px; font-size: 14px; background-color: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; } #send-btn:hover { background-color: #0056b3; } </style> </head> <body> <div> <h1>Real-Time Chat</h1> <div></div> <input type="text" placeholder="Enter your message"> <button>Send</button> </div> <script> const ws = new WebSocket('ws://' + location.host + '/ws'); const chat = document.getElementById('chat'); const messageInput = document.getElementById('message-input'); const sendBtn = document.getElementById('send-btn'); ws.onmessage = (event) => { const data = JSON.parse(event.data); const messageDiv = document.createElement('div'); messageDiv.className = 'message'; if (data.type === 'system') { messageDiv.className += ' system'; messageDiv.textContent = data.content; } else if (data.type === 'user') { messageDiv.innerHTML = `<span>${data.user}:</span> ${data.content}`; } chat.appendChild(messageDiv); chat.scrollTop = chat.scrollHeight; }; sendBtn.addEventListener('click', () => { const message = messageInput.value.trim(); if (message) { ws.send(JSON.stringify({ type: 'message', content: message })); messageInput.value = ''; } }); messageInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { sendBtn.click(); } }); </script> </body> </html> "#)}asyncfnws_handler( ws:WebSocketUpgrade, users:State<Users>, tx:State<broadcast::Sender<String>>,)->implIntoResponse{info!("New WebSocket connection");let user_id =uuid::Uuid::new_v4().to_string();let user_name =format!("User{}", user_id.chars().take(8).collect::<String>()); users.lock().await.insert(user_id.clone(),User{ id: user_id.clone(), name: user_name.clone()});let rx = tx.get_ref().subscribe(); ws.on_upgrade(|socket|handle_socket(socket, users, tx, rx, user_id, user_name))}asyncfnhandle_socket(mut socket:WebSocket, users:State<Users>, tx:State<broadcast::Sender<String>>,mut rx:broadcast::Receiver<String>, user_id:String, user_name:String,){// 发送系统消息通知用户加入let join_message =serde_json::json!({"type":"system","content":format!("{} joined the chat", user_name)}); tx.get_ref().send(serde_json::to_string(&join_message).unwrap()).unwrap();// 发送欢迎消息let welcome_message =serde_json::json!({"type":"system","content":format!("Welcome, {}!", user_name)}); socket.send(Message::Text(serde_json::to_string(&welcome_message).unwrap())).await.unwrap();// 心跳检测letmut heartbeat_interval =interval(Duration::from_secs(10));// 广播接收任务let broadcast_task =tokio::spawn(asyncmove{whileletOk(msg)= rx.recv().await{ifletErr(e)= socket.send(Message::Text(msg)).await{info!("Error sending broadcast message: {}", e);break;}}});// 消息处理任务let message_task =tokio::spawn(asyncmove{whileletSome(msg)= socket.recv().await{match msg {Ok(msg)=>{match msg {Message::Text(text)=>{info!("Received message: {}", text);let data:serde_json::Value=serde_json::from_str(&text).unwrap();if data["type"]=="message"{let user_message =serde_json::json!({"type":"user","user": user_name,"content": data["content"]}); tx.get_ref().send(serde_json::to_string(&user_message).unwrap()).unwrap();}}Message::Binary(data)=>{info!("Received binary message ({} bytes)", data.len());}Message::Ping(data)=>{info!("Received ping"); socket.send(Message::Pong(data)).await.unwrap();}Message::Pong(_)=>{info!("Received pong");}Message::Close(_)=>{info!("Connection closed");break;}}}Err(e)=>{info!("Error receiving message: {}", e);break;}}}});// 心跳检测任务let heartbeat_task =tokio::spawn(asyncmove{loop{tokio::select!{ _ = heartbeat_interval.tick()=>{ifletErr(e)= socket.send(Message::Ping(vec![])).await{info!("Error sending ping: {}", e);break;}} _ = message_task =>{break;} _ = broadcast_task =>{break;}}}});// 等待所有任务完成let _ =tokio::try_join!(heartbeat_task, message_task, broadcast_task);// 发送系统消息通知用户离开let leave_message =serde_json::json!({"type":"system","content":format!("{} left the chat", user_name)}); tx.get_ref().send(serde_json::to_string(&leave_message).unwrap()).unwrap();// 从用户列表中删除 users.lock().await.remove(&user_id);info!("WebSocket connection closed");}#[tokio::main]asyncfnmain(){tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::new("info")).with(tracing_subscriber::fmt::layer()).init();let users =Arc::new(Mutex::new(HashMap::new()));let(tx, _)=broadcast::channel(100);let app =Router::new().route("/",get(index)).route("/ws",get(ws_handler)).with_state(users).with_state(tx);let listener =tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();info!("WebSocket server running on http://0.0.0.0:3000");axum::serve(listener, app).await.unwrap();}

在Cargo.toml中添加依赖:

[dependencies] axum = { version = "0.5", features = ["ws"] } tokio = { version = "1.0", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" uuid = { version = "1.1", features = ["v4"] } 

4.3 客户端实现

客户端界面已经包含在服务端的index函数中,使用HTML和JavaScript实现。当用户访问http://localhost:3000时,会显示聊天界面。

4.4 性能测试与优化

我们可以使用ab(Apache Bench)工具测试服务端的HTTP性能:

ab -n1000-c100 http://localhost:3000/ 

或者使用wrk工具测试WebSocket连接的性能:

wrk -t12-c400-d30s http://localhost:3000/ws 

性能优化方法:

  • 使用连接池:对于数据库等资源,使用连接池可以避免频繁创建和销毁连接。
  • 优化消息处理:减少消息处理的耗时,提高处理效率。
  • 使用压缩算法:对消息进行压缩,减少传输数据量。
  • 使用负载均衡:对于高并发场景,使用负载均衡可以分散请求压力。

五、常见问题与最佳实践

5.1 WebSocket连接建立失败

问题:客户端无法与服务器建立WebSocket连接。

解决方案

  1. 检查服务器是否正在运行。
  2. 检查服务器地址和端口是否正确。
  3. 检查防火墙是否阻止了WebSocket连接。
  4. 检查服务器的CORS策略是否允许跨域请求。

5.2 消息发送失败

问题:客户端发送消息失败。

解决方案

  1. 检查WebSocket连接是否已经关闭。
  2. 检查消息格式是否正确。
  3. 检查服务器的消息处理逻辑是否有错误。
  4. 检查网络连接是否正常。

5.3 连接超时

问题:WebSocket连接在一段时间后自动断开。

解决方案

  1. 实现心跳检测与连接超时机制。
  2. 检查服务器的超时设置。
  3. 检查网络连接是否稳定。

5.4 消息乱序

问题:客户端接收到的消息顺序不正确。

解决方案

  1. 使用可靠的消息队列实现消息广播。
  2. 在消息中添加时间戳或序列号,客户端根据时间戳或序列号进行排序。

5.5 性能问题

问题:WebSocket服务的性能不佳。

解决方案

  1. 优化服务器的消息处理逻辑。
  2. 使用连接池和异步编程提高处理效率。
  3. 使用负载均衡分散请求压力。
  4. 对消息进行压缩,减少传输数据量。

六、总结

WebSocket协议为实时应用提供了高效的通信方式,Rust的异步编程能力使得构建高性能WebSocket服务变得简单。在本章中,我们介绍了WebSocket协议的基本概念、异步服务端和客户端的开发,以及实战项目的实现。

我们使用Axum框架实现了WebSocket服务端,支持消息广播、心跳检测和连接超时机制。我们还使用Tungstenite库实现了异步WebSocket客户端,支持重连机制。最后,我们构建了一个实时聊天应用,展示了WebSocket在实际项目中的应用。

通过学习本章内容,读者可以掌握Rust异步编程中WebSocket服务的开发方法,并了解常见问题和最佳实践。希望读者能够将这些知识应用到实际项目中,构建高性能的实时应用。

Read more

mysql-9.6.0-winx64 安装踩雷教程

mysql-9.6.0-winx64 安装踩雷教程

今天安装了mysql-9.6.0-winx64,有部分踩雷事项。 下载地址:mysql 1、D盘新建文件夹mysql,把文件压缩到这个文件夹底下 2、在安装包的根目录底下建一个my.ini文件。文件里面写的内容可以直接复制。 * 注意:很多旧教程里面的配置信息是错误和新的mysql不匹配。 会面临错误:MySQL 9.6.0 启动失败。根源是 配置项: default_authentication_plugin=mysql_native_password 在 9.6 版本中已被移除,同时因配置错误导致系统表 mysql.component 缺失。 * basedir具体的地址填写你自己的。 * datadir的data现在是没有的,要等后面初始化的时候才生成。 [mysqld]port=3307basedir=D:\\mysql\\mysql-9.6.0-winx64 datadir=D:

By Ne0inhk
Flutter 组件 csv2json 适配鸿蒙 HarmonyOS 实战:高性能异构数据转换,构建 CSV 流式解析与全栈式数据映射架构

Flutter 组件 csv2json 适配鸿蒙 HarmonyOS 实战:高性能异构数据转换,构建 CSV 流式解析与全栈式数据映射架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 csv2json 适配鸿蒙 HarmonyOS 实战:高性能异构数据转换,构建 CSV 流式解析与全栈式数据映射架构 前言 在鸿蒙(OpenHarmony)生态迈向工业数字化、涉及海量历史报表同步、离线数据采集及跨系统异构数据对齐的背景下,如何实现一种既能处理超大规模文本、又能保障转换极速且具备“非阻塞”特性的数据清洗方案,已成为决定应用数据吞吐能力与内存稳健性的核心因素。在鸿蒙设备这类强调 AOT 极致性能与受限内存足迹的环境下,如果应用依然采用原始的循环分割或同步全量加载 CSV,由于由于数据规模的膨胀,极易由于由于“内存瞬时爆表”导致鸿蒙应用的任务栈卡死。 我们需要一种能够流式处理(Streaming)、支持自动化字段映射(Auto-mapping)且具备零样板代码特性的转换方案。 csv2json 为 Flutter 开发者引入了“数据流变幻”范式。它将结构松散的 CSV 文本精确轰击为高维度的 JSON

By Ne0inhk
Flutter 组件 angel3_auth 适配鸿蒙 HarmonyOS 实战:多策略身份验证,构建全栈式安全鉴权与身份防腐架构

Flutter 组件 angel3_auth 适配鸿蒙 HarmonyOS 实战:多策略身份验证,构建全栈式安全鉴权与身份防腐架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 angel3_auth 适配鸿蒙 HarmonyOS 实战:多策略身份验证,构建全栈式安全鉴权与身份防腐架构 前言 在鸿蒙(OpenHarmony)生态迈向全栈式开发、涉及跨端统一登录、多因子安全验证(MFA)及高性能服务端 API 保护的背景下,如何构建一套坚固、可扩展且具备“多策略适配”能力的身份验证架构,已成为决定全栈系统安全等级与用户信任度的基石。在鸿蒙设备这类强调分布式安全域与跨端信任链的环境下,如果应用依然依赖硬编码的简单鉴权逻辑,由于由于身份上下文的复杂性,极易由于由于“鉴权粒度过粗”导致越权访问或遭受 CSRF/XSS 等复合型攻击。 我们需要一种能够解耦认证逻辑、支持多种插拔式策略(如 JWT、Local、OAuth2)且具备高度可定制性的鉴权中间件。 angel3_auth 为 Dart 全栈开发者引入了“

By Ne0inhk
黑马点评完整代码(RabbitMQ优化)+简历编写+面试重点 ⭐

黑马点评完整代码(RabbitMQ优化)+简历编写+面试重点 ⭐

简历上展示黑马点评 完整代码地址 微服务学成在线项目 前言 当初就是当作一个学习笔记和个人面试记录发的,没想到这么多人收藏浏览,还是感慨学Java的人确实多啊。 适合什么人看呢,我仅仅说说我个人的理解,因为我现在也是个经历秋招的双非学生。 1.初学者学习完Redis基础,想来个实战,黑马点评还是特别好的一个项目,基本包含了所有数据类型的运用和redis其他功能的扩展,这篇文章可以带你提炼重点,很好的走下流程。 2.但大部分人是冲着找实习和秋招去的,像我这种学历不高的秋招就不要写黑马点评了,即使包装,也会很容易看出来,我找实习的时候就被面试官问到这是不是黑马点评过,我们可以把其中的闪光点迁移到你找的其他项目中,比如缓存穿透雪崩击穿的解决方法,redisson分布式锁解决一人一单,这种在大多项目中都可以添加,自圆其说就行。 3.对于找实习的像大二,大三上的,想找个小厂试试手垂直向上升的,可以吃透它,面试官问你遇到的困难或者是你觉得难点,就可以重点讲一人一单这个解决方法和流程,越详细越好。 4.前提是大家不用直接用这套模板,太多人用了,这也是我从网上找的别人的,巧用AI让它改改项

By Ne0inhk