在这篇文章中,我们将在服务器端使用内存来存储客户端发送过来的数据。在实现数据存储之前,我们先在客户端使用clap库来解析命令行参数,并封装成命令发送给服务器。
clap解析命令行参数 在cargo.toml文件中加入clap依赖:
clap = {version = 3.1, features = [derive]}在src目录下新建args.rs文件,写入以下代码: 1use clap::parser; 2 3#[derive(debug, parser)] 4#[clap(name = kv_client)] 5pub enum clientargs { 6 get { 7 #[clap(long)] 8 key: string, 9 },10 set {11 #[clap(long)]12 key: string,13 #[clap(long)]14 value: string,15 },16 publish {17 #[clap(long)]18 topic: string,19 #[clap(long)]20 value: string,21 },22 subscribe {23 #[clap(long)]24 topic: string,25 },26 unsubscribe {27 #[clap(long)]28 topic: string,29 #[clap(long)]30 id: u32,31 }32}在src/lib.rs中加入以下代码:1mod args;2pub use args::*;修改src/bin/kv_client.rs代码: 1#[tokio::main] 2async fn main() -> result { 3 ...... 4 5 let client_args = clientargs::parse(); 6 7 // 解析命令行参数,生成命令 8 let cmd = process_args(client_args).await?; 9 // 命令编码10 cmd.encode(&mut buf).unwrap();11 // 发送命令12 stream.send(buf.freeze()).await.unwrap();13 info!(send command successed!);1415 loop {16 tokio::select! {17 some(ok(buf)) = stream.next() => {18 let cmd_res = cmdresponse::decode(&buf[..]).unwrap();19 info!(receive a response: {:?}, cmd_res);20 }21 }22 }23} 1// 生成cmdrequest命令 2async fn process_args(client_args: clientargs) -> result { 3 match client_args { 4 // 生成 get 命令 5 clientargs::get{key} => { 6 ok(cmdrequest::get(key)) 7 }, 8 // 生成 set 命令 9 clientargs::set{key, value} => {10 ok(cmdrequest::set(key, value.into()))11 },12 // 生成 publish 命令13 clientargs::publish{ topic, value } => {14 ok(cmdrequest::publish(topic, value.into()))15 },16 // 生成 subscribe 命令17 clientargs::subscribe{ topic } => {18 ok(cmdrequest::subscribe(topic))19 },20 // 生成 unsubscribe 命令21 clientargs::unsubscribe{topic, id} => {22 ok(cmdrequest::unsubscribe(topic, id))23 }24 }25}
打开一个终端,启动kv_sever。打开另一个终端执行以下命令来测试客户端:
rust_log=info cargo run --bin kv_client get --key mykeyrust_log=info cargo run --bin kv_client set --key mykey --value myvalue
服务器和客户端都正常处理了收到的请求和响应。
内存存储
我们使用dashmap crate在内存中存储数据,dashmap是一个快速的并发map。
我们先创建src/storage目录,再创建src/storage/mod.rs文件,然后在src/lib.rs文件中引入storage模块。
在src/storage/mod.rs文件中定义一个storage trait,以便于以后不同存储方式的扩展,代码如下:
1use std::error;23use bytes::bytes;45pub trait storage {6 fn get(&self, key: &str) -> result;7 fn set(&self, key: &str, value: bytes) -> result;8}
在src/storage目录下创建mem_storage.rs文件:
1#[derive(clone, debug, default)] 2pub struct memstorage { 3 map: dashmap 4} 5 6impl memstorage { 7 pub fn new() -> self { 8 self { 9 map: default::default(),10 }11 }12}1314impl storage for memstorage {15 fn get(&self, key: &str) -> result {16 ok(self.map.get(key).map(|v| v.value().clone()))17 }1819 fn set(&self, key: &str, value: bytes) -> result {20 self.map.insert(key.to_string(), value.clone());21 ok(some(value))22 }23}
修改kv_server.rs代码:
1async fn main() -> result { 2 ...... 3 4 // 初始化内存存储 5 let storage = arc::new(memstorage::new()); 6 7 loop { 8 ...... 910 let stor = storage.clone();1112 tokio::spawn(async move {13 // 使用frame的lengthdelimitedcodec进行编解码操作14 let mut stream = framed::new(stream, lengthdelimitedcodec::new());15 while let some(ok(mut buf)) = stream.next().await {16 // 对客户端发来的protobuf请求命令进行拆包17 let cmd_req = cmdrequest::decode(&buf[..]).unwrap();18 info!(receive a command: {:?}, cmd_req);1920 // 处理请求命令21 let cmd_res = process_cmd(cmd_req, &stor).await.unwrap();2223 buf.clear();2425 // 对protobuf的请求响应进行封包,然后发送给客户端。26 cmd_res.encode(&mut buf).unwrap();27 stream.send(buf.freeze()).await.unwrap();28 }29 info!(client {:?} disconnected, addr);30 });31 }32}3334// 处理请求命令,返回response35async fn process_cmd(req: cmdrequest, storage: &memstorage) -> result {36 match req {37 // 处理 get 命令38 cmdrequest{39 req_data:get(get {key})),40 } => {41 let value = storage.get(&key)?;42 ok(cmdresponse::new(200, get success.to_string(), value.unwrap_or_default()))43 }, 44 // 处理 set 命令45 cmdrequest{46 req_data:set(set {key, value})),47 } => {48 let value = storage.set(&key, value)?;49 ok(cmdresponse::new(200, set success.to_string(), value.unwrap_or_default()))50 }, 51 _ => err(invalid command.into())52 }53}
测试
1,打开一个终端,运行kv_server:
rust_log=info cargo run --bin kv_server
2,打开一个终端,运行kv_client,执行set命令:
rust_log=info cargo run --bin kv_client set --key mykey --value myvalue
3,打开一个终端,运行kv_client,执行get命令:rust_log=info cargo run --bin kv_client get --key mykey
执行结果:
info kv_client: send command successed!info kv_client: receive a response: cmdresponse { status: 200, message: get success, value: bmyvalue }
UBS:2030年自动驾驶出租车市场价值或达2万亿美元
稳压二极管的原理以及稳压管的选型技巧
使用VIvado封装自定IP并使用IP创建工程
工业智能网关助力打造智慧水务数据看板
第十六届电路保护与电磁兼容技术研讨会11月上海开幕
在服务器端使用内存来存储客户端发送过来的数据
GEACC-5595交换机
美国利用贸易大棒--剑指中国的“2025中国制造”
为什么自动驾驶的关键设备激光雷达主要依靠进口?
突破摩尔定律 台积电17年要试产7nm芯片
fest on Demand:12门基于FPGA设计的在线技术课程(可免费注册)
华为云CDN加速,真正的六边形战士
汽车芯片国产化为何步履艰难?技术差距到底有多大?
雷军超爱的:小米“拍照神器”,5寸屏+骁龙821+全金属
智能产品及配用电解决方案企业海兴电力发布2022第一季度报告
首战双11单品销售破10万,天猫助网红IP成功转型
5G时代,室内覆盖数字化是大势所趋
单片机实现延时的方法
接地电阻测试仪的组成_接地电阻测试仪如何接线
Cadence诠释EDA发展新引擎,打造智能系统设计基石