本系列是關(guān)于用Rust構(gòu)建一個(gè)KV Server的系列文章,內(nèi)容包括用tokio做底層異步網(wǎng)絡(luò)通訊、使用toml文件做配置、protobuf做傳輸協(xié)議、內(nèi)存/RockDB做數(shù)據(jù)存儲(chǔ)、事件通知、優(yōu)雅關(guān)機(jī)、并發(fā)連接限制及測(cè)量監(jiān)控等。
讓我們先使用tokio實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Client & Server通訊模型,然后在此基礎(chǔ)上逐步實(shí)現(xiàn)上面提及的各項(xiàng)內(nèi)容。
創(chuàng)建一個(gè)新項(xiàng)目:
cargo new --lib kvserver_rust
在Cargo.toml文件中加入tokio依賴(lài):
[dependencies]tokio = { version = "1.19", features = ["full"] }
Server
在src目錄下創(chuàng)建bin文件夾,然后創(chuàng)建kv_server.rs文件:
use anyhow::Result;use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, net::TcpListener,}; #[tokio::main]async fn main() -> Result<(), Box> { let addr = "127.0.0.1:19999"; let listener = TcpListener::bind(addr).await?; println!("Listening on {addr} ......"); loop { let (mut stream, addr) = listener.accept().await?; println!("Client: {:?} connected", addr); tokio::spawn(async move { let mut buf = vec![0u8; 1024]; loop { let n = stream.read(&mut buf).await.expect("從Socket讀取數(shù)據(jù)失敗!"); if n == 0 { return; } stream .write_all(&buf[0..n]) .await .expect("向Socket寫(xiě)入數(shù)據(jù)失敗!"); } }); }}
在"127.0.0.1:19999"地址監(jiān)聽(tīng)客戶(hù)端的連接,收到客戶(hù)端發(fā)來(lái)的信息后再返回給客戶(hù)端。
Client
在src/bin目錄下創(chuàng)建kv_client.rs文件:
use anyhow::Result;use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, net::TcpStream,}; #[tokio::main]async fn main() -> Result<(), Box> { let addr = "127.0.0.1:19999"; let mut stream = TcpStream::connect(addr).await?; let n = stream.write(b"Hello, world!").await?; println!("Send info successed!n = {n}"); let mut buf = vec![0u8; 1024]; let n = stream.read(&mut buf).await.expect("從Socket讀取數(shù)據(jù)失敗!"); println!("Receive info:{}, n = {n}", String::from_utf8(buf).unwrap()); Ok(())}
連接server端"127.0.0.1:19999"這個(gè)地址,向Server端發(fā)送"Hello, world!"消息,然后再接收Server端返回的消息。
打開(kāi)兩個(gè)終端,分別執(zhí)行:
cargo run --bin kv_servercargo run --bin kv_client
執(zhí)行結(jié)果
kv_server:
Listening on 127.0.0.1:19999 ......Client: 127.0.0.1:51724 connected
kv_client:
Send info successed!n = 13Receive info:Hello, world!, n = 13
配置文件
使用 toml 做配置文件,serde 來(lái)處理配置的序列化和反序列化。在項(xiàng)目根目錄下新建conf目錄,并在下面新建server.conf文件:
[listen_address]addr = '127.0.0.1:19999'
和client.conf文件:
[connect_address]server_addr = '127.0.0.1:19999'
新建src/config.rs文件:
use std::{error::Error, fs}; use serde::{Deserialize, Serialize}; // Server端配置#[derive(Debug, Serialize, Deserialize)]pub struct ServerConfig { pub listen_address: ListenAddress,} // 監(jiān)聽(tīng)地址#[derive(Debug, Serialize, Deserialize)]pub struct ListenAddress { pub addr: String,} // Client端配置#[derive(Debug, Serialize, Deserialize)]pub struct ClientConfig { pub connect_address: ConnectAddress,} // 連接地址#[derive(Debug, Serialize, Deserialize)]pub struct ConnectAddress { pub server_addr: String,} impl ServerConfig { // 加載Server端配置文件 pub fn load(path: &str) -> Result> { let config = fs::read_to_string(path)?; let server_conf: Self = toml::from_str(&config)?; Ok(server_conf) }} impl ClientConfig { // 加載Client端配置文件 pub fn load(path: &str) -> Result > { let config = fs::read_to_string(path)?; let client_conf: Self = toml::from_str(&config)?; Ok(client_conf) }}
然后在lib.rs中加入:
mod config;pub use config::*;
修改src/bin/kv_server.rs代碼:
#[tokio::main]async fn main() -> Result<(), Box> { let server_conf = ServerConfig::load("conf/server.conf")?; let listen_addr = server_conf.listen_address.addr; let listener = TcpListener::bind(&listen_addr).await?; println!("Listening on {} ......", listen_addr); ......}
修改src/bin/kv_client.rs代碼:
#[tokio::main]async fn main() -> Result<(), Box> { let client_conf = ClientConfig::load("conf/client.conf")?; let connect_addr = client_conf.connect_address.server_addr; let mut stream = TcpStream::connect(&connect_addr).await?; ......}
運(yùn)行kv_sever和kv_client后,執(zhí)行結(jié)果與上面一致。
-
監(jiān)控
+關(guān)注
關(guān)注
6文章
2307瀏覽量
56614 -
數(shù)據(jù)存儲(chǔ)
+關(guān)注
關(guān)注
5文章
997瀏覽量
51615 -
網(wǎng)絡(luò)通訊
+關(guān)注
關(guān)注
0文章
77瀏覽量
11502
原文標(biāo)題:用Rust實(shí)現(xiàn)KV Server-1 toml格式的配置文件
文章出處:【微信號(hào):Rust語(yǔ)言中文社區(qū),微信公眾號(hào):Rust語(yǔ)言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
只會(huì)用Python?教你在樹(shù)莓派上開(kāi)始使用Rust
使用rust開(kāi)發(fā)stm32系列教程
如何用 rust 語(yǔ)言開(kāi)發(fā) stm32
RUST在嵌入式開(kāi)發(fā)中的應(yīng)用是什么
在Rust代碼中加載靜態(tài)庫(kù)時(shí),出現(xiàn)錯(cuò)誤 ` rust-lld: error: undefined symbol: malloc `怎么解決?
如何用Foxmail Server搭建郵件服務(wù)器
如何用Windows 2000 Server充當(dāng)軟路由
Rust開(kāi)發(fā)操作系統(tǒng)教程之如何自制一個(gè)操作系統(tǒng)

使用tokio實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Client和Server通訊模型
使用Protobuf實(shí)現(xiàn)客戶(hù)端與服務(wù)器之間的通信協(xié)議層
Xilinx KV 260構(gòu)建一個(gè)人臉識(shí)別車(chē)庫(kù)門(mén)鎖

Rust構(gòu)建QEMU插件的框架
如何用Rust通過(guò)JNI和Java進(jìn)行交互
如何用Rust編寫(xiě)一個(gè)ChatGPT桌面應(yīng)用(保姆級(jí)教程)

如何用FastMCP快速開(kāi)發(fā)自己的MCP Server?

評(píng)論