当前位置: 首页 > news >正文

【数据序列化协议】Protocol Buffers

一、为什么需要序列化?

  • 数据跨平台/语言交互:
    • 不同编程语言(如 Java、Python、Go)的数据结构不兼容,序列化提供统一的数据表示。
    • 例如:Java 的 HashMap 和 Python 的 dict 需转换为通用格式(如 JSON、Protobuf)才能通信。
  • 网络传输优化:
    • 原始内存中的对象包含指针、元数据等冗余信息,无法直接传输。
    • 序列化后数据体积更小,减少带宽占用,提升传输效率。
  • 持久化存储:
    • 将对象转换为字节流或文本,保存到文件或数据库中,便于后续读取和恢复。
  • 数据版本兼容性:
    • 通过序列化协议(如 Protobuf)支持字段的增删改,避免因数据结构变化导致系统崩溃。

二、Protocol Buffers

1、Protobuf 简介

  • 官网地址:https://protobuf.dev/overview/
  • GitHub 项目地址:https://github.com/protocolbuffers/protobuf

Protocol Buffers(简称 Protobuf)是 Google 开发的一种高效、跨平台的数据序列化协议,专为结构化数据的存储和通信设计。

它通过简洁的接口定义语言(IDL)描述数据结构,并生成高效的序列化代码,广泛应用于微服务通信(如 gRPC)、大数据存储等场景。

Protocol Buffers 的核心优势:

  • 高效性:二进制编码,体积比 XML/JSON 小 3-10 倍,序列化速度快 5-100 倍
  • 跨语言支持:支持 Java、C++、Python、Go 等主流语言,代码自动生成
  • 强类型约束:通过 .proto 文件明确定义数据结构,减少运行时错误
  • 向后兼容性:通过字段编号(Tag)管理版本演进,新旧版本可共存
  • 可扩展性:支持新增字段、嵌套消息、枚举、Map 等复杂结构

2、Protobuf 语法详解

2.1 基本结构

.proto 文件中定义数据结构和接口(示例:hello.proto):

syntax = "proto3";              //  指定使用 proto3 语法option java_package="com.example";     //  生成文件所在路径及包名。service serviceName {			// 定义服务,在这个服务中需要有一个方法,这个方法可以接受客户端的参数,再返回服务端的响应。 rpc GetUser (UserRequest) returns (UserResponse);
}message UserRequest {           //  定义消息类型,命名规范:使⽤驼峰命名法,⾸字⺟⼤写。string name = 1;              //  字段类型 + 名称 + 标签号(不可重复)int32 age = 2;repeated string hobbies = 3;  //  repeated 表示返回多个数据,可理解为Java List
}
  • .proto 文件命名应该使⽤全⼩写字⺟命名,多个字⺟之间⽤ _ 连接。 例如:lower_snake_case.proto
  • 书写 .proto ⽂件代码时,应使⽤ 2 个空格的缩进。
  • 向⽂件添加注释,可使⽤ // 或者 /* … */

在利用 Protobuf 进行网络数据传输时,确保通信双方拥有一致的 .proto 文件至关重要。缺少了相应的 .proto 文件,通信任何一方都无法生成必要的工具函数代码,进而无法解析接收到的消息数据。

与 JSON 这种文本格式不同,后者即便在没有 JSON.parse 反序列化函数的情况下,人们仍能大致推断出消息内容。相比之下,Protobuf 序列化后的数据是二进制字节流,它并不适合人类阅读,且必须通过特定的反序列化函数才能正确解读数据。

Protobuf 的这种设计在提高数据安全性方面具有优势,因为缺少 .proto 文件就无法解读数据内容。然而,这也意味着在通信双方之间需要维护一致的 .proto 文件,随着项目的扩展,这可能会带来额外的维护成本。

2.2 字段规则

  • 字段标签号(Tag):唯一标识字段(1-15 占 1 字节,16-2047 占 2 字节)
  • 标量类型:string, int32, bool, bytes, double 等
  • 复合类型:
    • repeated:数组或列表
    • oneof:多个字段中只能同时设置一个
    • map:键值对(如 map<string, int32>)
  • 嵌套消息:消息内定义其他消息

2.3 版本控制策略

  • 新增字段:使用新标签号,旧代码会忽略未知字段
  • 弃用字段:标记 reserved 防止误用
    reserved 2, 15 to 20; 	// 保留标签号
    reserved "email";		// 保留字段名
    

3、Protobuf 序列化机制

3.1 二进制编码原理

  • TLV 结构:每个字段按 Tag-Length-Value 编码(无冗余字段名)
    • Tag:字段标签号 + 数据类型(如 Varint, 64-bit, Length-delimited)
    • Value:根据类型压缩存储(如 Varint 对整数进行变长编码)
  • 示例:int32 age = 2; → 标签号 2 对应二进制 0x10,值 25 编码为 0x19

3.2 性能对比

格式编码方式可读性体积解析速度
XML文本
JSON文本较大较慢
Protobuf二进制极快

4、protoc 编译器

protoc 是 Protocol Buffers 的核心编译器,用于将 .proto 文件编译为不同语言的代码(如 Java、C++、Python 等)。

(1)安装编译器 protoc

官网安装文档:https://protobuf.dev/installation/

在 https://github.com/protocolbuffers/protobuf/releases 上下载对应的版本,然后配置环境变量:

# 配置环境变量
cat > ~/.zshrc <<EOF
# Protocol Buffers
export PATH="$PATH:/Users/zs/App/env/protoc-25/bin"
EOF# 验证
protoc --version

(2)IDEA配置protobuf插件

IntelliJ IDEASettingsPluginsMarketPlace,输入 Protocol Buffers,点击 Install

在这里插入图片描述

(3)基础命令结构

protoc [OPTIONS] PROTO_FILESPROTO_FILES					# 待编译的 .proto 文件路径(如 src/main/proto/hello.proto)OPTIONS:						# 控制代码生成和编译行为的参数--<lang>_out=OUT_DIR		# 指定生成代码的语言和输出目录(如 --java_out、--python_out)(--java_out=src/main/java)--plugin=EXECUTABLE		# 指定自定义插件(如 gRPC 插件)	(--plugin=protoc-gen-grpc-java=/path/to/plugin)--grpc-<lang>_out			# 生成 gRPC 服务代码(需安装对应语言的 gRPC 插件)	(--grpc-java_out=src/main/java)-IPATH, --proto_path=PATH	# 指定 .proto 文件的搜索路径(可多次使用)	(-I src/main/proto -I ../shared/proto)--descriptor_set_out=FILE	# 生成描述符文件(包含所有编译的 .proto 信息)	(--descriptor_set_out=my_protos.desc)--version					# 显示 protoc 版本	( protoc --version)-h, --help					# 显示帮助信息	(protoc --help)--encode=MESSAGE			# 将文本消息编码为二进制(需指定 .proto)	(protoc --encode=MyMessage my.proto < input.txt)--decode=MESSAGE			# 将二进制消息解码为文本	(protoc --decode=MyMessage) my.proto < input.bin

示例:

# 场景 1:生成 Java 代码
protoc \--proto_path=src/main/proto \   # .proto 文件搜索路径--java_out=src/main/java \      # Java 代码输出目录src/main/proto/hello.proto      # 待编译的 proto 文件# 场景 2:生成 Java gRPC 代码
# 需提前安装 grpc-java 插件(protoc-gen-grpc-java)
protoc \--proto_path=src/main/proto \--java_out=src/main/java \--grpc-java_out=src/main/java \  # 生成 gRPC 服务代码--plugin=protoc-gen-grpc-java=/path/to/protoc-gen-grpc-java \  # 显式指定插件路径src/main/proto/hello.proto# 场景 3:多文件批量编译
protoc \-I src/main/proto \-I ../shared/protos \          # 多路径导入--java_out=out/java \src/main/proto/*.proto \       # 编译所有 proto 文件../shared/protos/utils/*.proto# 场景 4:生成描述符文件(Descriptor Set)
protoc \--proto_path=src/main/proto \--descriptor_set_out=my_protos.desc \  # 输出描述符文件--include_imports \                   # 包含所有依赖src/main/proto/hello.proto

5、Protobuf 开发示例

Java + gRpc:开发一个通讯录服务,根据联系人名字返回其电话号码。

需要注意的是:grpc服务调用底层已经用protobuf实现了序列化与反序列化,故无需手动序列化。

  • 创建 Maven 项目 contract
    在这里插入图片描述
  • contract 项目添加三个模块:grpc-api、grpc-service、grpc-client
    、
  • grpc-api 模块修改内容:
    • 在 grpc-api 模块的 src/main目录下新建目录proto,创建 contract.proto ⽂件
      syntax = "proto3";option java_multiple_files = false;
      option java_package = "com.example";
      option java_outer_classname = "ContactProto"message ContractRequest{string name = 1;
      }message ContractResponse{string tel = 1;
      }service ContractService{rpc query(ContractRequest) returns (ContractResponse);
      }
      
    • 修改 grpc-api 模块pom.xml文件,导入 gprc-java 相关依赖
      <dependency><groupId>io.grpc</groupId><artifactId>grpc-netty-shaded</artifactId><version>1.70.0</version><scope>runtime</scope>
      </dependency>
      <dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId><version>1.70.0</version>
      </dependency>
      <dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId><version>1.70.0</version>
      </dependency>
      <dependency> <!-- necessary for Java 9+ --><groupId>org.apache.tomcat</groupId><artifactId>annotations-api</artifactId><version>6.0.53</version><scope>provided</scope>
      </dependency>
      
    • 修改 grpc-api 模块pom.xml文件,导入 protobuf 插件用于生成代码(也可以用protoc编译器生成)
      <build>  <!-- 在Maven构建过程中自动检测操作系统类型,并根据操作系统选择合适的protoc编译器和gRPC Java插件版本,从而编译.proto文件并生成相应的Java代码 --><extensions><extension> <!--  检测操作系统的类型和版本   --><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.7.1</version></extension></extensions><plugins><plugin> <!-- 编译.proto文件,生成Java代码 --><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><!-- 指定用于编译的protoc编译器版本和分类器(classifier)--><protocArtifact>com.google.protobuf:protoc:3.25.5:exe:${os.detected.classifier}</protocArtifact><!-- 指定用于编译的插件ID,这里使用的是grpc-java,表示将使用gRPC Java的插件来生成额外的Java代码。 --><pluginId>grpc-java</pluginId><!-- 指定gRPC Java插件的版本和分类器  --><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.70.0:exe:${os.detected.classifier}</pluginArtifact><!-- 指定代码生成位置 --><outputDirectory>${basedir}/src/main/java</outputDirectory><!-- 是否清空生成路径下的资源 --><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><!-- compile目标用于编译标准的Protobuf文件 --><goal>compile</goal><!-- compile-custom目标通常用于编译那些需要特殊处理的Protobuf文件(如果有的话)。 --><goal>compile-custom</goal></goals></execution></executions></plugin></plugins>
      </build>
      
      ${os.detected.classifier} 可能会飘红:Cannot resolve symbol 'os. detected. classifier' ,点击 Reimport 即可
      在这里插入图片描述
    • 生成代码
      (base) zs@Mac contract % cd grpc-api 
      (base) zs@Mac grpc-api % mvn protobuf:compile protobuf:compile-custom
      
      生成的代码在 contract/grpc-api/src/main/java/com/example
      在这里插入图片描述
      ContractServiceGrpc类结构:
      • 核心类
        类名作用
        ContractServiceGrpc入口类,包含服务描述符、方法定义和 Stub 工厂方法(如 newStub)
        ContractServiceImplBase服务端基类,需要继承并实现 query 方法的具体逻辑
        ContractServiceBlockingStub客户端同步调用存根,直接阻塞等待响应(如 query 方法调用)
        ContractServiceFutureStub客户端异步调用存根,返回 ListenableFuture 对象处理响应
        ContractServiceStub客户端异步流式存根,使用 StreamObserver 处理请求和响应
        ServiceDescriptor服务的元数据描述,包含方法名、请求响应类型等信息
      • 关键方法
        方法功能
        getQueryMethod()返回 query 方法的描述符(请求类型 ContractRequest,响应类型 ContractResponse)。
        newBlockingStub(Channel)创建同步客户端存根,用于阻塞式调用服务端方法。
        bindService(AsyncService)将服务端实现类绑定到 gRPC 服务器,生成 ServerServiceDefinition。
  • grpc-server 模块
    • 导入依赖:
      <dependency><groupId>com.example</groupId><artifactId>grpc-api</artifactId><version>1.0-SNAPSHOT</version>
      </dependency>
      
    • 编写服务类 ContractServiceImpl:
      package com.example.service;import com.example.ContactProto;
      import com.example.ContractServiceGrpc;
      import io.grpc.stub.StreamObserver;public class ContractServiceImpl extends ContractServiceGrpc.ContractServiceImplBase {@Overridepublic void query(ContactProto.ContractRequest request, StreamObserver<ContactProto.ContractResponse> responseObserver) {//1.业务处理System.out.println("Receive client data: " + request.getName());try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}//2.封装响应ContactProto.ContractResponse response = ContactProto.ContractResponse.newBuilder().setTel("+100 110120119").build();//3.响应responseObserver.onNext(response);responseObserver.onCompleted();}
      }
      
    • 编写启动类Main.java
      package com.example;import com.example.service.ContractServiceImpl;
      import io.grpc.ServerBuilder;import java.io.IOException;public class Main {public static void main(String[] args) throws IOException, InterruptedException {ServerBuilder.forPort(9000).addService(new ContractServiceImpl()).build().start().awaitTermination();}}
      
  • grpc-client
    • 导入依赖:
      <dependency><groupId>com.example</groupId><artifactId>grpc-api</artifactId><version>1.0-SNAPSHOT</version>
      </dependency>
      
    • 编写调用类Main.java
      package com.example;import com.google.common.util.concurrent.FutureCallback;
      import com.google.common.util.concurrent.Futures;
      import com.google.common.util.concurrent.ListenableFuture;
      import io.grpc.ManagedChannel;
      import io.grpc.ManagedChannelBuilder;
      import io.grpc.stub.StreamObserver;import java.util.Iterator;
      import java.util.concurrent.Executors;
      import java.util.concurrent.TimeUnit;public class Main {public static void main(String[] args) {//1.创建通信管道ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 9000).usePlaintext().build();try{//2.获取代理对象 stubContractServiceGrpc.ContractServiceBlockingStub contractServiceBlockingStub = ContractServiceGrpc.newBlockingStub(managedChannel);//3.创建请求对象ContactProto.ContractRequest contractRequest = ContactProto.ContractRequest.newBuilder().setName("Mary").build();//4.grpc调用ContactProto.ContractResponse contractResponse = contractServiceBlockingStub.query(contractRequest);//5.业务处理System.out.println("unary rpc call: " + contractResponse.getTel());} catch (Exception e){System.out.println(e.getMessage());;} finally {managedChannel.shutdown();}}
      }
      

5、Protobuf 与 gRPC 的协作

  • 服务定义:在 .proto 中定义 RPC 方法(如 rpc SayHello(…))
  • 代码生成:protoc 生成服务端和客户端桩代码(如 GreeterGrpc.java)
  • 数据传输:gRPC 使用 Protobuf 作为默认序列化协议,高效传输二进制数据

6、适用场景与局限性

适用场景:

  • 微服务间通信(如 gRPC)
  • 需要高性能序列化的场景(如游戏、IoT)
  • 大数据存储(如 Hadoop、Kafka 消息格式)

局限性:

  • 可读性差:二进制数据无法直接阅读
  • 需预定义 Schema:灵活性不如 JSON(适合结构化数据)
  • 版本管理复杂度:需谨慎处理字段变更

7、最佳实践

  • 合理规划标签号:频繁使用的字段用 1-15 以节省空间
  • 避免修改字段类型:可能导致解析错误
  • 使用 optional 字段(proto3 默认)以支持字段缺失
  • 版本兼容性测试:确保新旧版本协议可互操作

十、资料

  • 深入protobuf(Protocol Buffers)原理:简化你的数据序列化
  • ProtoBuf 入门详解
  • protobuf简介

相关文章:

【数据序列化协议】Protocol Buffers

一、为什么需要序列化&#xff1f; 数据跨平台/语言交互&#xff1a; 不同编程语言&#xff08;如 Java、Python、Go&#xff09;的数据结构不兼容&#xff0c;序列化提供统一的数据表示。例如&#xff1a;Java 的 HashMap 和 Python 的 dict 需转换为通用格式&#xff08;如 …...

基于 Python 的电影市场预测分析系统设计与实现(源码 + 文档)

大家好&#xff0c;今天要和大家聊的是一款基于 Python 的“电影市场预测分析”系统的设计与实现。项目源码以及部署相关事宜请联系我&#xff0c;文末附上联系方式。 项目简介 基于 Python 的“电影市场预测分析”系统主要面向以下用户角色&#xff1a;电影制片方、电影发行…...

计算机三级网络技术知识汇总【6】

第六章 交换机及其配置 1. 交换机基础 1.1 基本概念 局域网交换机是一种基于 MAC 地址识别&#xff0c;完成转发数据帧功能的一种网络连接设备。 工作在数据链路层&#xff0c;根据进入端口数据帧中的 MAC 地址进行数据帧的过滤、转发&#xff08;也是交换机的工作原理&…...

2025教育与科研领域实战全解析:DeepSeek赋能细分场景深度指南(附全流程案例与资源)

🚀 2025教育与科研领域实战全解析:DeepSeek赋能细分场景深度指南(附全流程案例与资源)🚀 📚 目录 DeepSeek在教育与科研中的核心价值教学场景应用:从备课到课堂管理的全流程革新科研场景应用:从数据分析到论文写作的智能跃迁师生协同创新:AI赋能的个性化学习与科研…...

Linux 命令大全完整版(10)

4. 压缩与解压缩命令 gzip(gnu zip) 功能说明&#xff1a;压缩文件。语  法&#xff1a;gzip [-acdfhlLnNqrtvV][-S <压缩字尾字符串>][-<压缩效率>][–best/fast][文件…] 或 gzip [-acdfhlLnNqrtvV][-S <压缩字尾字符串>][-<压缩效率>][–best/f…...

彻底卸载kubeadm安装的k8s集群

目录 一、删除资源 二、停止k8s服务 三、重置集群 四、卸载k8s安装包 五、清理残留文件和目录 六、删除k8s相关镜像 七、重启服务器 一、删除资源 # 删除集群中的所有资源&#xff0c;包括 Pod、Deployment、Service&#xff0c;任意节点执行 kubectl delete --all pod…...

vue+element-plus简洁完美实现淘宝网站模板

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.详情 4.购物车 5.登陆页 三、源码实现 1.路由配置 2.依赖包 四、总结 一、项目介绍 项目在线预览&#xff1a;点击访问 本项目为vue项目&#xff0c;参考淘宝官方样式为主题来设计元素&#xff0c;简洁美观&…...

学习aigc

DALLE2 论文 Hierarchical Text-Conditional Image Generation with CLIP Latents [2204.06125] Hierarchical Text-Conditional Image Generation with CLIP LatentsAbstract page for arXiv paper 2204.06125: Hierarchical Text-Conditional Image Generation with CLIP L…...

深度学习-127-LangGraph之基础知识(四)自定义状态添加额外字段的聊天机器人

文章目录 1 自定义状态2 自定义工具2.1 完善工具human_assistance2.2 浏览器工具baidu_search3 聊天机器人3.1 绑定工具的聊天模型3.2 聊天机器人(带记忆)4 调用图4.1 调用工具时中断4.2 人工提供信息恢复4.3 查询存储的状态4.4 手动更新状态5 参考附录使用LangGraph,在状态中…...

广东英语十二种应用文模版范文

1. 邀请信&#xff08;Invitation Letter&#xff09; 模版 Dear [Recipients Name],I hope this letter finds you well. I am writing to invite you to [Event Name] which will be held on [Date] at [Location]. The event will start at [Time] and we would be deligh…...

python使用httpx_sse调用sse流式接口对响应格式为application/json的错误信息的处理

目录 问题描述方案 问题描述 调用sse流式接口使用httpx_sse的方式 import httpxfrom httpx_sse import connect_sse# 省略无关代码try:with httpx.Client() as client:with connect_sse(client, "GET", url, paramsparam) as event_source:clear_textbox(response_t…...

Leetcode-407. Trapping Rain Water II [C++][Java]

目录 一、题目描述 二、解题思路 【C】 【Java】 Leetcode-407. Trapping Rain Water IIhttps://leetcode.com/problems/trapping-rain-water-ii/description/ 一、题目描述 Given an m x n integer matrix heightMap representing the height of each unit cell in a 2D…...

详解 torch.triu:上三角矩阵的高效构造(中英双语)

详解 torch.triu&#xff1a;上三角矩阵的高效构造 在深度学习和矩阵运算中&#xff0c;我们经常需要构造上三角矩阵&#xff08;Upper Triangular Matrix&#xff09;&#xff0c;其中主对角线以下的元素全部设为 0。PyTorch 提供了一个高效的函数 torch.triu()&#xff0c;用…...

[ TypeScript ] “undefined extends xxx“ 总是为 true 的 bug

版本号 "typescript": "^5.7.3", "unplugin": "^2.2.0",说明 在使用 unplugin 时 , 我定义插件的参数是 必填的, 使用时却是一个可空参数, 不传参也不会报错, (options?: UserOptions) > Return &#x1f632;&#x1f632;&…...

高清下载油管视频到本地

下载工具并安装: yt-dlp官网地址&#xff1a; GitHub - yt-dlp/yt-dlp: A feature-rich command-line audio/video downloader ffmpeg官网地址&#xff1a; Download FFmpeg 注&#xff1a;记住为其添加环境变量 操作命令&#xff1a; 该指令表示以720p码率下载VIDEO_UR…...

Hadoop常用操作命令

在NameNode节点格式化集群 初始化集群 hdfs namenode -format启动HDFS sbin/start-dfs.sh启动yarn sbin/start-yarn.sh启动NodeManager yarn-daemon.sh start nodemanager启动DataNode hadoop-daemon.sh start datanode启动SecondaryNameNode hadoop-daemon.sh start se…...

[HOT 100] 2439. 最小化数组中的最大值

文章目录 1. 题目链接2. 题目描述3. 题目示例4. 解题思路5. 题解代码6. 复杂度分析 1. 题目链接 2439. 最小化数组中的最大值 - 力扣&#xff08;LeetCode&#xff09; 2. 题目描述 给你一个下标从 0 开始的数组 nums &#xff0c;它含有 n 个非负整数。 每一步操作中&#…...

【JavaEE进阶】图书管理系统 - 贰

目录 &#x1f332;前言 &#x1f384;设计数据库 &#x1f343;引⼊MyBatis和MySQL驱动依赖 &#x1f333;Model创建 &#x1f38d;约定前后端交互接口 &#x1f340;服务器代码 &#x1f6a9;控制层 &#x1f6a9;业务层 &#x1f6a9;数据层 &#x1f334;前端代码…...

Vue学习教程-14内置指令

文章目录 前言一、v-text指令二、v-html指令三、v-cloak指令四、v-once指令五、v-pre指令六、其他指令 前言 Vue.js 提供了许多内置指令&#xff08;Directives&#xff09;&#xff0c;这些指令用于在模板中添加特殊功能。内置指令以 v- 前缀开始。 v-text : 更新元素的 tex…...

【蓝桥杯单片机】客观题

一、第十三届省赛&#xff08;一&#xff09; 二、第十三届省赛&#xff08;二&#xff09;...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...