Rust : windows下protobuf和压缩传输方案

此前dbpystream库是用python开发 web api。今天在rust中试用一下protobuf。

本文关键词:编译器、protobuf、proto文件、序列化、zstd压缩,build。

一、 protobuf编译器下载

具体见相关文章。没有编译器,protobuf无法运行。
windows参见:

https://blog.csdn.net/wowotuo/article/details/139458846?spm=1001.2014.3001.5502。

二、proto文件的准备

proto文件中主要模拟了一个dbpystream中一个get_price函数的输入和输出的格式,输入HistoryBarRequest ,输出HistoryBarResponse。HistoryBarResponse中,有代码名称,日期,开盘价,最高价等。
在格式中,包括了string,TimeStamp,double; 其中repeated就是vec格式。

syntax = "proto3";
package dbdata;
import public "google/protobuf/timestamp.proto";
service DataService {rpc query (HistoryBarRequest) returns (HistoryBarRequest) {}
}
service Login{rpc auth (Auth) returns (Response) {}
}
message Auth{string id =1; string password=2; 
}
message HistoryBarRequest {string security  = 1;string frequency = 2;FieldParam fields     = 3;google.protobuf.Timestamp start_date = 4;//收集时间google.protobuf.Timestamp end_date = 5;//收集时间bool is_fq  =6 ; 
}
message HistoryBarResponse{repeated string securitycode = 1;repeated google.protobuf.Timestamp  datetime =2;repeated double  open = 3;repeated double  high = 4;repeated double close = 5;repeated double low =6;repeated double volume=7;repeated double amount=8;repeated sint64 is_fq = 9;
}message FieldParam{bool is_all = 1;
}message Response {bool status = 1;bytes msg   = 2;string error = 3;
}

三、toml文件、文件目录结构、build.rs
1、toml文件有

[package]
name = "clap-2"
version = "0.1.0"
edition = "2021"# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies]
axum = "0.7.5" # web 服务器
anyhow = "1" # 错误处理
reqwest = { version = "0.12.4", features = ["json"] } # HTTP 客户端
tokio = { version = "1", features = ["full"] } # 异步处理库
prost = "0.12.6"
# Only necessary if using Protobuf well-known types:
prost-types = "0.12.6"
serde = { version = "1", features = ["derive"] } # 序列化/反序列化数据
polars = { version = "0.39.0", features = ["json"]}
chrono = { version = "0.4", features = ["unstable-locales"] }
zstd = "0.13" # 压缩库
[build-dependencies]
prost-build = "0.12.6" # 编译 protobuf

上面polars,chrono,prost-types,prost-build,prost,zstd是关键库,其它暂时可以不看。

2、目录结构
具体如下:

PS D:\my_program\clap-2> tree /F
卷 新加卷 的文件夹 PATH 列表
卷序列号为 D855-8BFE
D:.
│  .gitignore
│  build.rs
│  Cargo.lock
│  Cargo.toml
│  dbdata.proto
│
└─src│  main.rs│└─pbdbdata.rsmod.rs

可见,在src/目录下,手动创建了一个pb文件夹,存放未来生成的dbdata.proto文件。

3、build.rs
在src同级目录上(如上),创建build.rs,具体如下:

fn main() {prost_build::Config::new().out_dir("src/pb")//设置proto输出目录.compile_protos(&["dbdata.proto"], &["."])//我们要处理的proto文件.unwrap();
} 

运行cargo build,即生成了dbdata.rs,具体内容如下:

// This file is @generated by prost-build.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Auth {#[prost(string, tag = "1")]pub id: ::prost::alloc::string::String,#[prost(string, tag = "2")]pub password: ::prost::alloc::string::String,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HistoryBarRequest {#[prost(string, tag = "1")]pub security: ::prost::alloc::string::String,#[prost(string, tag = "2")]pub frequency: ::prost::alloc::string::String,#[prost(message, optional, tag = "3")]pub fields: ::core::option::Option<FieldParam>,/// 收集时间#[prost(message, optional, tag = "4")]pub start_date: ::core::option::Option<::prost_types::Timestamp>,/// 收集时间#[prost(message, optional, tag = "5")]pub end_date: ::core::option::Option<::prost_types::Timestamp>,#[prost(bool, tag = "6")]pub is_fq: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HistoryBarResponse {#[prost(string, repeated, tag = "1")]pub securitycode: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,#[prost(message, repeated, tag = "2")]pub datetime: ::prost::alloc::vec::Vec<::prost_types::Timestamp>,#[prost(double, repeated, tag = "3")]pub open: ::prost::alloc::vec::Vec<f64>,#[prost(double, repeated, tag = "4")]pub high: ::prost::alloc::vec::Vec<f64>,#[prost(double, repeated, tag = "5")]pub close: ::prost::alloc::vec::Vec<f64>,#[prost(double, repeated, tag = "6")]pub low: ::prost::alloc::vec::Vec<f64>,#[prost(double, repeated, tag = "7")]pub volume: ::prost::alloc::vec::Vec<f64>,#[prost(double, repeated, tag = "8")]pub amount: ::prost::alloc::vec::Vec<f64>,#[prost(sint64, repeated, tag = "9")]pub is_fq: ::prost::alloc::vec::Vec<i64>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct FieldParam {#[prost(bool, tag = "1")]pub is_all: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Response {#[prost(bool, tag = "1")]pub status: bool,#[prost(bytes = "vec", tag = "2")]pub msg: ::prost::alloc::vec::Vec<u8>,#[prost(string, tag = "3")]pub error: ::prost::alloc::string::String,
}

4、mod.rs
在pb目录下,创建mod.rs:

pub mod dbdata;

四、原始数据、main.rs

1、原始数据

这个原始数据csv的格式,一共是5499行,9列。
在这里插入图片描述
即收到request后,将发送这个数据内容出去。
文件名称是"C:\Users\Desktop\test.csv"。
这里采用了polars来读取csv文件。模拟的是服务端读相关数据库(如clickhouse)。

2、main.rs

下面的main.rs模拟了收到resquest,发送response的过程。这个过程可以用web框架,如axum,也可以用grpc框架。这部分不是今天的重点。

需要说明的是:在序列化HistoryBarResponse的基础上,并用zstd库进行了压缩打包,进一步减少了二进制对象的大小,有利于网络传输。

use pb::dbdata::{self, HistoryBarResponse,Response};
mod pb;
use prost_types::Timestamp;
use std::time::{Duration, SystemTime,Instant};
use polars::prelude::*;
use chrono::{NaiveDate, NaiveDateTime,NaiveTime};
use zstd;
fn main() ->Result<(),PolarsError>{let request = dbdata::HistoryBarRequest {security: String::from("600036.XSHG"),frequency: String::from("1minute"),fields: Some(dbdata::FieldParam {is_all:true}),start_date: Some(prost_types::Timestamp::from(SystemTime::now()-Duration::from_secs(3600*12*250))),end_date:Some(prost_types::Timestamp::from(SystemTime::now())),is_fq:true,};println!("模拟收到request:{:?}",request);println!("模拟开始进行相应的数据处理.....");let now_0 = Instant::now();let file = r"C:\Users\hongsl\Desktop\test.csv";let df: DataFrame = CsvReader::from_path(file)?.has_header(true).finish().unwrap();println!("starting...");println!("csv =>df 文件的行列信息 : {:?}",df.shape());println!("读csv花时: {:?} 秒!", now_0.elapsed().as_secs_f32());let now_1 = Instant::now();let res_raw = HistoryBarResponse{securitycode : df.column("securitycode")?.str()?.into_no_null_iter().map(|s|String::from(s)).collect(),datetime:df.column("date")?.str()?.into_no_null_iter().map(|t| convert(t)).collect(),open:df.column("open")?.f64()?.into_no_null_iter().collect(),high:df.column("high")?.f64()?.into_no_null_iter().collect(),close:df.column("close")?.f64()?.into_no_null_iter().collect(),low:df.column("low")?.f64()?.into_no_null_iter().collect(),volume:df.column("volume")?.i64()?.into_no_null_iter().map(|v|v as f64).collect(),amount:df.column("amount")?.f64()?.into_no_null_iter().collect(),is_fq:df.column("is_fq")?.i64()?.into_no_null_iter().collect(),};println!("准备historybarresponse花时: {:?} 秒!", now_1.elapsed().as_secs_f32());//println!("{:?}", res);let now_2 = Instant::now();let encoded_raw = prost::Message::encode_to_vec(&res_raw);println!("historybarresponse => encoded 花时: {:?} 秒!", now_2.elapsed().as_secs_f32());let compression_level = 3;// 服务端对序列化对象进行压缩,let now_3 = Instant::now();let compressed = zstd::encode_all(&*encoded_raw, compression_level).unwrap();println!("historybarresponse encoded =>compressed 花时: {:?} 秒!", now_2.elapsed().as_secs_f32());// 服务端模拟通过web或grpc发送let res = Response{status:true,msg: compressed,error:String::from(""),};let encoded = prost::Message::encode_to_vec(&res);println!("服务端从csv =>compressed 后发出:{:?}",now_0.elapsed().as_secs_f32());let now_4 = Instant::now();// 模拟客户端接收到web或grpc相应的数据对象let decoded_raw =  < pb::dbdata::Response as prost::Message>::decode(&encoded[..]).unwrap();// 并进行解压,得到Histlet decoded_raw: Vec<u8> = zstd::decode_all(decoded_raw.msg.as_slice()).unwrap();let decoded  = < pb::dbdata::HistoryBarResponse as prost::Message>::decode(&decoded_raw[..]).unwrap();println!("模拟发送相应的数据: {:?}", &decoded.securitycode[0]);println!("客户端解压数据花时:{:?}",now_4.elapsed().as_secs_f32());Ok(())
}fn convert(dt_str:&str) ->Timestamp {let naive_date = NaiveDate::parse_from_str(dt_str, "%Y/%m/%d").unwrap();let nano_second = NaiveTime::from_hms_milli_opt(0, 0, 0, 0).unwrap();let dt: NaiveDateTime = naive_date.and_time(nano_second );Timestamp{seconds:dt.and_utc().timestamp(),nanos:0,}
}

运行如下:

模拟收到request:HistoryBarRequest { security: "600036.XSHG", frequency: "1minute", fields: Some(FieldParam { 
is_all: true }), start_date: Some(Timestamp { seconds: 1707372680, nanos: 689289100 }), end_date: Some(Timestamp { seconds: 1718172680, nanos: 689290500 }), is_fq: true }
模拟开始进行相应的数据处理.....
starting...
csv =>df 文件的行列信息 : (5499, 9)
读csv花时: 0.0031793 秒!
准备historybarresponse花时: 0.0007998 秒!
historybarresponse => encoded 花时: 0.0002774 秒!
historybarresponse encoded =>compressed 花时: 0.0017601 秒!
服务端从csv =>compressed 后发出:0.0061509
模拟发送相应的数据: "600036.XSHG"
客户端解压数据花时:0.0015236

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/349652.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工作组局域网-ARP欺骗-攻击防御单双向

免责声明:本文仅做技术交流与学习... 目录 断网限制-单向 环境: 演示: win10: 欺骗前 欺骗后 kali: kali执行命令: win10结果: 劫持数据-双向 欺骗&#xff1a; 网络分析&#xff1a; 防御--动态解析改静态 中间人攻击 断网限制-单向 环境: 靶机:win10 攻击机:kali…

【JavaEE】Spring Boot MyBatis详解(一)

一.MyBatis的基本概念与相关配置. 1.基本概念 MyBatis是一款优秀的持久层框架&#xff0c;用于简化JDBC的开发。MyBatis本是Apache的一个开源项目iBatis&#xff0c;2010年这个项目由apache迁移到了google code&#xff0c;并且改名为MyBatis. 2013年11月迁移到Github.持久层…

Spring Boot:Java 应用开发高效之道

Spring Boot 是一种革命性的框架&#xff0c;旨在简化 Java 应用的创建和部署过程。通过自动化配置和简化项目搭建流程&#xff0c;Spring Boot 大大加速了开发周期&#xff0c;让 Java 应用开发变得更加高效和便捷。 核心优势&#xff1a; 快速启动和简化配置&#xff1a;Spr…

智慧公安指挥中心大数据信息化两中心两基地系统方案

1.1 系统建设目标 本系统是一个汇接全市的报警求助的大型通信指挥系统&#xff0c;技术难度较高、可靠性要求高&#xff0c;技术路线的选择至关重要。 在充分考虑XX市公安局的业务需要&#xff0c;利用现代通信及计算机网络技术的基础上&#xff0c;最大程度地实现资源整合、…

数据结构和矩阵细节用法:double、cell和complex #matlab

矩阵建立 建立矩阵用[]&#xff1b; 矩阵的同一行内的元素用逗号或者空格隔开&#xff1b; 矩阵的不同行的元素用分号隔开 eg. 矩阵 A 1 2 3 4 5 6 7 8 9 在matlab中矩阵A表示为&#xff1a; clc;clear; A[1,2,3;4,5,6;7,8,9]; %或者A[1 2 3;4 5 …

苹果AI来了,ios18史诗级发布

今天凌晨1点&#xff0c;苹果举行了WWDC开发者大会&#xff0c;正式发布了 全新iOS 18、iPadOS 18、watchOS 11、tvOS 18、macOS 等以及Apple Intelligence的个人化智能系统 苏音给大家汇总下&#xff0c;ios18的更新内容以及苹果的AI。 本次更新&#xff0c;官方带来的title…

关于怎么用Cubemx生成的USBHID设备实现读取一体的鼠标键盘设备(改进版)

主要最近做了一个要用STM32实现读取鼠标键盘一体的那种USB设备&#xff0c;STM32的界面上要和电脑一样的能通过这个USB接口实现鼠标移动&#xff0c;键盘的按键。然后我就很自然的去参考了正点原子的例程&#xff0c;可是找了一圈&#xff0c;发现正点原子好像用的库函数&#…

46.Python-web框架-Django - 多语言配置

目录 1.Django 多语言基础知识 1.1什么是Django国际化和本地化&#xff1f; 1.2Django LANGUAGE_CODE 1.3关于languages 1.4RequestContext对象针对翻译的变量 2.windows系统下的依赖 3.django多语言配置 3.1settings.py配置 引用gettext_lazy 配置多语言中间件&#x…

【机器学习300问】110、什么是Lasso回归模型?

LASSO回归的全称是Least Absolute Shrinkage and Selection Operator&#xff0c;中文叫“最小绝对收缩和选择算子”&#xff0c;用一个比喻来初步感受一下它的作用&#xff1a; 想象你在整理一个杂乱无章的房间&#xff0c;里面堆满了各种物品&#xff08;代表众多的预测变量&…

快捷回复话术分享:如何应对顾客愤怒骂人?

在客服的日常工作中&#xff0c;面对情绪激动、甚至愤怒发泄骂人的顾客是常见的挑战。初入此行业的小伙伴们往往在遭遇顾客的激烈情绪时感到手足无措&#xff0c;不知道如何妥善回应。为此&#xff0c;本文将分享一些实用的快捷回复话术和技巧&#xff0c;帮助新手客服更好地处…

flink源码系列:RPC通信

这里写目录标题 1. 本节课目的2.开始本节内容2.1.RPC概念3.2.大数据组件常见的RPC实现技术3.3.Pekko&#xff08;Akka&#xff09;3.3.1. Akka、Pekko基本概念3.3.2.Pekko Demo事例3.3.2.1.PekkoData 类3.3.2.2.PekkoRpcReceiverActor类3.3.2.3.PekkoRpcSenderActor 类3.3.2.4.…

使用QT制作QQ登录界面

mywidget.cpp #include "mywidget.h"Mywidget::Mywidget(QWidget *parent): QWidget(parent) {/********制作一个QQ登录界面*********************/this->resize(535,415);//设置登录窗口大小this->setFixedSize(535,415);//固定窗口大小this->setWindowTi…

图片转Base64

在Python中, 可以使用内置的base64模块以及图像处理库(如PIL, 也称为Pillow)来将图片转换为Base64编码的字符串. 以下是一个简单的示例, 说明如何实现这一过程:首先, 需要安装Pillow库(如果尚未安装), 可以使用pip来安装: pip install pillow然后, 可以使用以下Python代码将图片…

【kyuubi-spark】从0-1部署kyuubi集成spark执行spark sql到k8s读取iceberg的minio数据

一、背景 团队在升级大数据架构 前端使用trino查询&#xff0c;对trino也进行了很多优化&#xff0c;目前测试来看&#xff0c;运行还算稳定&#xff0c;但是不可避免的trino的任务总会出现失败的情况。原来的架构是trino失败后去跑hive&#xff0c;而hive是跑mapreduce依赖于…

VBA语言専攻每周资料领取通知

通知20240615 各位学员∶本周MF系列VBA技术资料增加626-630讲&#xff0c;T3学员看到通知后请免费领取,领取时间6月14日晚上19:00-6月15日晚上20:00。本次增加内容&#xff1a; MF626:将列标题转换为数字 MF627:拆分日期和时间 MF628:从工作表中随机取数 MF629:从工作表中…

【MySQL】日志详解

本文使用的MySQL版本是8 日志概览 它们记录了数据库系统中的不同操作和事件&#xff0c;以便于故障排除、性能优化和数据恢复。本文将介绍MySQL中常见的几种日志&#xff0c;同时也会介绍一点常用的选项。 官方文档&#xff1a;MySQL :: MySQL 8.0 Reference Manual :: 7.4 M…

【FAS】《CN103106397B》

原文 CN103106397B-基于亮瞳效应的人脸活体检测方法-授权-2013.01.19 华南理工大学 方法 / 点评 核心方法用的是传统的形态学和模板匹配&#xff0c;亮点是双红外发射器做差分 差分&#xff1a;所述FPGA芯片控制两组红外光源&#xff08;一近一远&#xff09;交替亮灭&…

【算法专题--链表】相交链表--高频面试题(图文详解,小白一看就会!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐双指针 --- 数学思维 ⭐双指针 --- 按链表长度计算 &#x1f95d; 判断相交 &#x1f347; 求出交点 &#x1f34d;实现步骤 四、总结与提炼 五、共勉 一、前言 相交链表这道题&#xff0c;可以说是--链表专题--&#xf…

【C++进阶学习】第一弹——继承(上)——探索代码复用的乐趣

前言&#xff1a; 在前面&#xff0c;我们已经将C的初阶部分全部讲完了&#xff0c;包括类与对象、STL、栈和队列等众多内容&#xff0c;今天我们就进入C进阶部分的学习&#xff0c;今天先来学习第一弹——继承 目录 一、什么是继承&#xff1f;为什么会有继承&#xff1f; 二…

C语言详解(文件操作)1

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…