在服务器端使用内存来存储客户端发送过来的数据

在这篇文章中,我们将在服务器端使用内存来存储客户端发送过来的数据。在实现数据存储之前,我们先在客户端使用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发展新引擎,打造智能系统设计基石