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

news2024/12/23 16:36:31

此前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
    │
    └─pb
            dbdata.rs
            mod.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、原始数据准备

这个原始数据的格式,即收到request后,将发送这个数据内容出去。
在这里插入图片描述文件名称是"C:\Users\Desktop\test.csv"。
这里采用了polars来读取csv文件。

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};
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 file = r"C:\Users\hongsl\Desktop\test.csv";
    let df: DataFrame = CsvReader::from_path(file)?
            .has_header(true)
            .finish().unwrap();
    println!("starting...");
    println!("df: {:?}",df);
    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!("{:?}", res);
    let encoded_raw = prost::Message::encode_to_vec(&res_raw);
    let compression_level = 3;
    // 服务端对序列化对象进行压缩,
    let compressed = zstd::encode_all(&*encoded_raw, compression_level).unwrap();
    // 服务端模拟通过web或grpc发送
    let res = Response{
        status:true,
        msg: compressed,
        error:String::from(""),
    };
    let encoded = prost::Message::encode_to_vec(&res);

    // 模拟客户端接收到web或grpc相应的数据对象
    let decoded_raw =  < pb::dbdata::Response as prost::Message>::decode(&encoded[..]).unwrap();
    
    // 并进行解压,得到Hist
    let 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]);
    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: 1707035277, nanos: 595181300 }), end_date: Some(Timestamp { seconds: 1717835277, nanos: 595183100 }), is_fq: true }
模拟开始进行相应的数据处理.....
starting...
df: shape: (482, 9)
┌──────────────┬───────────┬────────┬────────┬───┬────────┬────────┬─────────────┬───────┐
│ securitycode ┆ dateopen   ┆ high   ┆ … ┆ close  ┆ volume ┆ amount      ┆ is_fq │
│ ---          ┆ ---       ┆ ---    ┆ ---    ┆   ┆ ---    ┆ ---    ┆ ---         ┆ ---   │
│ str          ┆ str       ┆ f64    ┆ f64    ┆   ┆ f64    ┆ i64    ┆ f64         ┆ i64   │
╞══════════════╪═══════════╪════════╪════════╪═══╪════════╪════════╪═════════════╪═══════╡
│ 600036.XSHG  ┆ 2021/2/3  ┆ 1210.41222.3 ┆ … ┆ 1221.5122341.4943831e7 ┆ 1     │
│ 600037.XSHG  ┆ 2021/2/4  ┆ 1210.51222.4 ┆ … ┆ 1221.6122351.4946276e7 ┆ 1     │
│ 600038.XSHG  ┆ 2021/2/5  ┆ 1210.61222.5 ┆ … ┆ 1221.7122361.4949e7    ┆ 1     │
│ 600039.XSHG  ┆ 2021/2/6  ┆ 1210.71222.6 ┆ … ┆ 1221.8122371.4951e7    ┆ 1     │
│ 600040.XSHG  ┆ 2021/2/7  ┆ 1210.81222.7 ┆ … ┆ 1221.9122381.4954e7    ┆ 1     │
│ …            ┆ …         ┆ …      ┆ …      ┆ … ┆ …      ┆ …      ┆ …           ┆ …     │
│ 600513.XSHG  ┆ 2022/5/26 ┆ 1258.11270.0 ┆ … ┆ 1269.2127111.6133e7    ┆ 1     │
│ 600514.XSHG  ┆ 2022/5/27 ┆ 1258.21270.1 ┆ … ┆ 1269.3127121.6135e7    ┆ 1     │
│ 600515.XSHG  ┆ 2022/5/28 ┆ 1258.31270.2 ┆ … ┆ 1269.4127131.6138e7    ┆ 1     │
│ 600516.XSHG  ┆ 2022/5/29 ┆ 1258.41270.3 ┆ … ┆ 1269.5127141.6140423e7 ┆ 1     │
│ 600517.XSHG  ┆ 2022/5/30 ┆ 1258.51270.4 ┆ … ┆ 1269.6127151.6142964e7 ┆ 1     │
└──────────────┴───────────┴────────┴────────┴───┴────────┴────────┴─────────────┴───────┘
模拟接收并解析发送相应的数据: "600036.XSHG"

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多年不见,我美少女又回来了!

各位&#xff0c;可能很多人都不记得我了&#xff0c;上学的时候喜欢记学习笔记&#xff0c;好多学弟学妹们经常来我的博客看笔记&#xff0c;对于学习也有帮助。 时过境迁&#xff0c;生活中的琐事和繁忙的工作&#xff0c;真的自顾不暇… 还记得之前说要转型给大家分享内容运…

量产导入 | DFT和ATE概述

什么是DFT DFT(Design for Test),即可测性设计。 一切为了芯片流片后测试所加入的逻辑设计,都叫DFT。 DFT只是为了测试芯片制造过程中有没有缺陷,而不是用来验证芯片功能的,芯片功能的完善应该应该是在芯片开发过程用先进验证方法学去做的。 芯片制造过程相当复杂,工艺缺陷…

LabVIEW程序内存泄漏分析与解决方案

维护他人编写的LabVIEW程序时&#xff0c;若发现程序运行时间越长&#xff0c;占用内存越大直至崩溃&#xff0c;通常是内存泄漏导致的。本文从多角度分析内存泄漏的可能原因&#xff0c;包括数组和字符串处理、未释放的资源、循环中的对象创建等&#xff0c;并提供具体的解决方…

SamSung PM9B1 1TB性能实测

** SamSung PM9B1 1TB性能实测 ** 一颗主控一颗NAND FLASH 单面器件布局&#xff0c;PMIC集成电源芯片DC\DC模组 PCIE Gen4.0X4 性能3673MB2954MB 工作状态功耗4.1w左右&#xff0c;待机状态功耗1.2W左右 全盘读速度2000MB左右 H2缓内速度1.2G H2缓外速度730MB H2读速度1.3G …

牛客little w and Discretization

玩一下样例发现&#xff0c;只要找到mex就可以知道有((1-mex)的值)所在的位置离散化后和原本的值是一样的&#xff0c;所以询问区间的长度-&#xff08;1-mex&#xff09;有几个值就是答案&#xff0c;数据范围3e5&#xff0c;莫队值域分块求区间mex,计算1-mex有几个位置属于这…

mmdeploy环境部署流程

参考&#xff1a;mmdeploy/docs/zh_cn/01-how-to-build/linux-x86_64.md at main open-mmlab/mmdeploy (github.com) 从零入门《openmmlab》mmdeploy[1]环境安装及简单上手_哔哩哔哩_bilibili 我的环境&#xff1a; docker容器&#xff0c;ubuntu20.04&#xff0c;cuda11.7…

迁移学习助力机器学习实践应用

大家好&#xff0c;迁移学习是一种技术&#xff0c;能使机器利用从以前任务中获得的知识来提高对新任务的泛化能力。作为ChatGPT和Google Gemini等模型的核心原理&#xff0c;迁移学习在长文档总结、复杂文章撰写、旅行规划以及诗歌和歌曲创作等重要任务中发挥着关键作用。 本…

Docker 安装gitLab

目录 1. 安装 Docker 2. 拉取 GitLab 镜像 3. 创建并运行 GitLab 容器 4. 登录GitLab 修改下载地址 修改账号密码 前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&#xff0c;我们往往容易…

解决关于git clone 带子模块的项目得到的源码不完整,导致编译失败的解决办法

在使用 git 克隆一个项目的时候&#xff0c;你可能会碰到克隆后编译失败的情况&#xff0c;经过查找&#xff0c;发现原来是缺少一些文件&#xff0c;这些文件都有一个特点&#xff0c;如图&#xff1a; 要解决这个问题&#xff0c;需要在clone 命令的基础上加上一些参数 &…

Nature Communications|基于离子导电和强力蚕丝纤维的智能感知纺织品 (柔性智能织物/可穿戴电子/柔性纤维传感/柔性电子)

2024年4月17日,清华大学张莹莹教授(Yingying Zhang)课题组,在《Nature Communications》上发布了一篇题为“Intelligent perceptual textiles based on ionicconductive and strong silk fibers”的论文。论文内容如下: 一、 摘要 将纺织品赋予感知功能,类似于人类皮肤,…

Linux--08---挂载分区

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.查看系统磁盘分区情况1.lsblk 查看2.fdisk -l 2.挂载未分区磁盘1. 创建分区2. 格式化分区3. 创建挂载点4. 挂载分区5. 更新 /etc/fstab6.验证挂载 3.修改挂载的磁…

0.18微米 BCD 工艺兼容的准垂直功率 DMOS 器件结构参数对 RON,sp 的影响

来源&#xff1a;Influence of Structure Parameters on the RON,sp of Quasi-Vertical Power DMOS Compatible with 0.18μm BCD Process&#xff08;ISPSD 24年&#xff09; 摘要 “Lateral double-diffused MOSFET (LDMOS)是应用于功率电子领域最常见的器件之一,得益于其可…

【论文】2405.Phased Consistency Model(港中文提出了AI绘画加速模型,一步采样生成图像,支持SD1.5,SDXL)

论文&#xff1a;https://arxiv.org/abs/2405.18407 &#xff08;2024.05.30发布&#xff09; 代码&#xff1a;https://github.com/G-U-N/Phased-Consistency-Model 一、论文要解决什么问题&#xff1f;效果如何&#xff1f; (需要先了解LCM模型) (阶段性一致性模型:朝着稳定…

express入门02静态资源托管

目录 1 搭建静态资源结构2 代码助手3 多目录托管4 服务器热启动总结 上一篇我们讲解了使用express搭建服务器的过程&#xff0c;服务器搭建好了之后&#xff0c;除了在地址栏里输入URL发起get请求或者post请求外&#xff0c;通常我们还需要访问静态资源&#xff0c;比如html、c…

一文看懂linux ext4文件系统工作原理

前言 Linux系统中的ext2、ext3、ext4 文件系统&#xff0c;它们都有很强的向后和向前兼容性&#xff0c;可以在数据不丢失的情况下进行文件系统的升级。目前ext4是一个相对较成熟、稳定且高效的文件系统&#xff0c;适用于绝大部分规模和需求的Linux环境。 ext4它突出的特点有&…

修改SubVI的LabVIEW默认搜索路径

在启动顶级VI后&#xff0c;LabVIEW可能会遇到找不到subVI的情况。这通常是由于subVI的路径发生了变化或没有被正确配置。 LabVIEW默认搜索路径 默认情况下&#xff0c;LabVIEW会按以下顺序搜索文件位置&#xff08;*表示LabVIEW将搜索子目录&#xff09;&#xff1a; <t…

PS系统教程15

仿制图章与修饰照片 仿制图章工具使用&#xff08;S&#xff09;使用方法&#xff1a;按住Alt键进行采样选定照片新建图层&#xff08;方便修改&#xff09;按住Alt键&#xff0c;进行吸取进行采样复制 下面那个石柱是我们复制的石柱 多余的部分用历史画笔工具涂抹掉一部分 案…

外汇天眼:Brighter Super 选择 State Street 作为托管和管理合作伙伴

State Street Corporation&#xff08;纽约证券交易所代码&#xff1a;STT&#xff09;今日宣布&#xff0c;其已被选为 Brighter Super 成员所投资的超过300亿澳元基金的托管人和管理员。 State Street 将为 Brighter Super 涵盖多种资产类别的130多个投资组合提供广泛的服务…

一文带你入门 - Qt绘图QPainter

QPaintEvent绘图事件: QPaintEvent 是 Qt 框架中一个重要的事件类&#xff0c;专门用于处理绘图事件。当 Qt 视图组件需要重绘自己的一部分时&#xff0c;就会产生 QPaintEvent 事件。这通常发生在以下几种情况&#xff1a; 1. 窗口第一次显示时&#xff1a;当窗口或控件第一次…

探秘C++ STL中的Stack与Queue:数据结构的艺术与实践

在C的世界里&#xff0c;标准模板库(STL)无疑是一颗璀璨的明珠&#xff0c;它不仅极大地丰富了C的生态系统&#xff0c;更为开发者提供了强大的工具箱。其中&#xff0c;stack和queue作为两种基础而重要的数据结构&#xff0c;扮演着不可或缺的角色。本文将深入剖析这两个容器适…