惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
Webroot Blog
Webroot Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Threat Research - Cisco Blogs
V2EX - 技术
V2EX - 技术
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
S
Schneier on Security
I
InfoQ
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The GitHub Blog
The GitHub Blog
S
Security @ Cisco Blogs
O
OpenAI News
W
WeLiveSecurity
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Simon Willison's Weblog
Simon Willison's Weblog
人人都是产品经理
人人都是产品经理
Cloudbric
Cloudbric
The Last Watchdog
The Last Watchdog
The Hacker News
The Hacker News
Google Online Security Blog
Google Online Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
NISL@THU
NISL@THU
T
Tailwind CSS Blog
V
Visual Studio Blog
PCI Perspectives
PCI Perspectives
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
D
DataBreaches.Net
B
Blog RSS Feed
N
News and Events Feed by Topic
N
News and Events Feed by Topic
H
Heimdal Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
腾讯CDC
Latest news
Latest news
V
Vulnerabilities – Threatpost
Hacker News: Ask HN
Hacker News: Ask HN
WordPress大学
WordPress大学
V
V2EX
aimingoo的专栏
aimingoo的专栏
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Register - Security
The Register - Security
Help Net Security
Help Net Security

I'm OWenT

国产大模型(GLM 5.1、Kimi K2.6)真实场景效果和 Coding Plan 额度测试 新版本libatapp的连接管理——从etcd服务发现到拓扑驱动的自动重连 新版本libatbus的设计变更——从树形路由到拓扑驱动 Protobuf又一坑 - C++标准和ABI兼容性 AI真好用-给Blog主题统一加mermaid,chart.js,excalidraw,draw.io的多种引入方式支持 给内网部署Squid-通用HTTP下载缓存 UE使用CodeChecker和clang-tidy生成静态分析报告 找出UE的循环依赖 C++小协程栈和临时变量及作用域的栈溢出问题分析 游戏服务的可观测性能力建设(C++生态) 指标上报的多线程优化和多拉取源点优化 协程(libcopp)的Channel功能和CPU命中率优化 通用RPC代码生成器 实现strong_rc_ptr(比shared_ptr更快的引用计数智能指针) 手夯一个STL allocator和对象内存分析组件 std::condition_variable 的信号丢失问题 踩坑一处(GCC)STL std::async 实现BUG导致的crash问题 GCC 14的一个warning to error BUG 给xresloader(Excel导表工具)增强UE读表支持(包含蓝图,Blueprint) Opentelemetry社区在gRPC的几个链接问题(静态库和动态库混用,musl工具链,符号裁剪) Excel转表工具(xresloader)的新验证器(验证外部Excel和文本数据,唯一性和自定义规则) protobuf v22和gRPC v1.55版本升级的依赖变化和upb适配 关于protobuf近期版本(v20/v3.20+)和 gRPC v1.54版本在某些编译环境下的一些链接和编译问题 xresloader-Excel导表工具链的近期变更汇总 打通游戏服务端框架的C++20协程改造的最后一环 Opentelemetry-cpp的Logs模块标准更新(涉及近期版本:1.8-1.9的BREAK CHANGES) 给cmake-toolset和工具链(curl等)加HTTP/2和HTTP/3支持 又开新坑之 coredns 插件: nftables和filter 关于opentelemetry-cpp社区对于C++ Head Only组件单例和符号可见性的讨论小记 填个转表工具 xresloader 去年的坑(数组尾部裁剪) 集成 upb 和 lua binding 的踩坑小记 libcopp对C++20协程的接入和接口设计 再度优化GCC、LLVM、Clang、libc++、libc++abi等套件的构建脚本 游戏服务的分布式事务优化(二)- 事务管理 游戏服务的分布式事务优化(一)- Write Ahead Log(WAL) 模块 记录一些bazel适配用编译选项 测试现代化硬件C++浮点数性能和一致性 适配Boringssl和OpenSSL 3.0 近期cmake-toolset的一些适配问题 C++20 Text Formatting/fmtlib 适配问题小记 再次重构LLVM+Clang+libcxx+libc++abi+其他相关工具的构建流程 重构基于CMake的构建工具链 新版GCC和LLVM+Clang终于Release啦 折腾一下nftables下的双拨 [C++20] Module partitions和符号交叉引用(声明和实现分离) [Rust] 实现一个线程安全且迭代器可以保存的链表 基于protobuf的代码生成 几个使用protobuf中C++接口的Arena的坑 Amazon Aurora DB存储引擎论文阅读小记 近期对libatapp的一些优化调整(增加服务发现和连接管理,支持yaml等) xresloader转表工具链增加了一些新功能(map,oneof支持,输出矩阵,基于模板引擎的加载代码生成等) 在游戏服务器中使用分布式事务 libcopp接入C++20 Coroutine和一些过渡期的设计 libatbus 的大幅优化 nftables初体验 容器配置开发环境小计 PALM Tree - 适合多核并发架构的B+树 - 论文阅读小记 跨平台协程库 - libcopp 简介 C++20 Coroutine 性能测试 (附带和libcopp/libco/libgo/goroutine/linux ucontext对比) 尝鲜Github Action 一些xresloader(转表工具)的改进 protobuf、flatbuffer、msgpack 针对小数据包的简单对比 协程框架(libcopp) 小幅优化 Excel转表工具(xresloader) 增加protobuf插件功能和集成 UnrealEngine 支持 Anna(支持任意扩展和超高性能的KV数据库系统)阅读笔记 C++20 Coroutine libcopp merge boost.context 1.69.0 Google去中心化分布式系统论文三件套(Percolator、Spanner、F1)读后感 Rust玩具-企业微信机器人通用服务 使用ELK辅助监控开发测试环境服务质量和问题定位 2018年的新通用伪随机数算法(xoshiro / xoroshiro)的C++(head only)实现 Webpack+vue+boostrap+ejs构建Web版GM工具 Rust的第二次接触-写个小服务器程序 理解和适配AEAD加密套件 atsf4g-co的进化:协程框架v2、对象路由系统和一些其他细节优化 协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比 可执行文件压缩 初识Rust 使用restructedtext编写xresloader文档 atframework的etcd模块化重构 C++的backtrace ECDH椭圆双曲线(比DH快10倍的密钥交换)算法简介和封装 protobuf-net的动态Message实现 atgateway内置协议流程优化-加密、算法协商和ECDH 整理一波软件源镜像同步工具+DevOps工具 Blog切换到Hugo libcopp v2的第一波优化完成 libcopp(v2) vs goroutine性能测试 libcopp的线程安全、栈池和merge boost.context 1.64.0 GCC 7和LLVM+Clang+libc++abi 4.0的构建脚本 libatbus的几个藏得很深的bug 用cmake交叉编译到iOS和Android 开源项目得一些小维护 atapp的c binding和c#适配 对象路由系统设计 2016年总结 近期的一个协程流程BUG 重写了llvm+clang+libc++和libc++abi的构建脚本 atsf4g完整游戏工程示例|I'm OWenT atframework基本框架已经完成|I'm OWenT
pbc的proto3接入
owent · 2017-09-17 · via I'm OWenT

blog-website

Protobuf 的 proto3发布也有挺长一段时间了。现在很多新项目慢慢转变用proto3来开发。这篇文章主要记录一下我在给pbc写对proto3支持时的一些信息,也许对其他童鞋也有点助益。抛砖引玉一下。

简介

pbc云风开发的一个纯C的读写protobuf的很小巧的库,配合上它提供的lua-5.1和lua-5.3的binding可以很容易地在lua里完成对pb文件的注册和打解包。应该很多人都知道这个组件。

但是后来云风自己又发明了个sproto,然后主推在他的skynet框架中使用sproto,于是pbc就不再有功能维护了。

我们之前的也尝试直接使用了proto3,也是因为在迁移期,所以并没有使用全部的特性。但是仍然有一些向前不兼容的细节需要处理一下,所以有了这个改造

Proto2和Proto3的差异

因为主要目的是兼容,所以下面会列出proto3得不同之处,并且会标注处理方法。

  1. 移除 required属性和默认值

    这部分原先本身有很多逻辑容易楼判定,所以影响不大。只是每个字段不再是三态(无/默认值/自定义值),只有两态(默认值/自定义值)。这回影响比如脏数据差分更新得逻辑,因为不再有has_xxx接口来判定数据是否有变更了。不过pbc也有对默认值数据做裁剪,所以这里反而是和pbc不谋而合了,所以这里无需修改。

  2. 移除unknown fields(据说以后会加回来)

    这里主要影响更新以后客户端和服务器版本不一致得时候得数据处理。本身游戏逻辑在协议设计得时候就会考虑这个问题,如果非强制更新,会允许缺失或者忽略一些数据。所以本身影响不大。

  3. 移除extension,增加Any类型代替

    同样,目前我还没有用到过这个特性。也暂时忽略。

  4. 枚举类型语义变更,现在必须提供默认值

    这个影响proto文件得语法,这个对proto文件得改造量有点大。但对pbc也没什么影响。

  5. 增加了新的类型map、timestamp等

    这些类型我大致看了下实现,基本上就是当成message/bytes来用,proto2是可以正常解出得。只是多做了一层结构化而已。现在得pbc即便不支持,也不影响以前得使用方式,只不过得手动打解包一层。而底层得protobuf得基础数据结构并没有变化。而且我对pbc底层结构并没有那么熟,所以也没太多时间做完这个后再去做各项测试。而且一般我们逻辑都会自己建立这种索引和结构所以不太用得到。

  6. 官方支持json格式和检查utf-8编码

    这个就是方便一点,以前我们自己写过一个protobuf到json得中间件。另外很多protobuf得代码里写死了UTF-8。所以加个检查也是对得。对兼容性也没啥影响。

  7. 不再支持Group

    这个我一直觉得很鸡肋,去掉也好。

  8. 所有数字类型的repeated字段现在默认是packed=true的了。

    protobuf的repeated字段有两种处理方式:第一种是由多个key-value对组成,也就是说repeated的数据中,key可能会出现多次;第二种是先有一个varint,表示个数,后面跟N个value。具体编码可以参见我以前写得 《理解Protobuf的数据编码规则》。前一种就是packed=false,反之后一种就是packed=true。这里会影响解包时的组织结构,所以是一个需要修改pbc的地方。

  9. C++ API的重要更新:允许自定义内存分配区

    其他语言的我没看,C++的众多变化里我也就觉得这一个比较重要。这是可以自定义内存分配区。因为以前protobuf的message的嵌套结构,都是new出来的。估计是这样多了以后内存碎片和分配性能都比较受影响吧,所以多了这么个类似内存池的东西。感觉还是蛮有用的。虽然我一直用jemalloc所以也不太care这个malloc的开销(只要别乱搞,这里的分配开销和逻辑比任然是九牛一毛)。

大体上差异就这么多了,当然后面的版本会再有些修订也未可知。但是总体看来,要做到打解包的兼容性适配,只有移除需要改的地方,就是repeated字段那里。其他的也就是proto文件的语法有些变化,其他的都还兼容。

涉及的代码就一个文件: register.c,改成如下的样子。

static void
_register_field(struct pbc_rmessage * field, struct _field * f, struct _stringpool *pool) {
	int origin_label;
	int packed;
	f->id = pbc_rmessage_integer(field, "number", 0 , 0);
	f->type = pbc_rmessage_integer(field, "type", 0 , 0);	// enum
	origin_label = pbc_rmessage_integer(field, "label", 0, 0) - 1; // LABEL_OPTIONAL = 0
	f->label = origin_label;
	// 最优情况是能判定出pb文件是proto2还是proto3。
	// 但是pb文件里似乎并没有这种信息,所以proto2和proto3的库选择上只能二选一了。
	switch(f->type) { // 就是这里获取到field之后需要看看是否是数字类型,如果是数字类型,那么默认的repeated字段要改为packed类型。
	case PTYPE_DOUBLE:
	case PTYPE_FLOAT:
	case PTYPE_INT64:
	case PTYPE_SINT64:  
	case PTYPE_INT32:
	case PTYPE_SINT32:  
	case PTYPE_UINT32:
	case PTYPE_ENUM:
	case PTYPE_UINT64:
	case PTYPE_FIXED32:
	case PTYPE_SFIXED32:
	case PTYPE_SFIXED64:
	case PTYPE_FIXED64:
	case PTYPE_BOOL:
		if (f->label == LABEL_REPEATED) {
			f->label = LABEL_PACKED;
		}
		break;
    default:
        break;
    }
	
	if (pbc_rmessage_size(field , "options") > 0) {
		struct pbc_rmessage * options = pbc_rmessage_message(field, "options" , 0);
		// 这里是为了如果用户显式设定了packed,则以用户设定为准。这里还要处理非数字类型的情况。
		if (pbc_rmessage_size(options, "packed") > 0) {
			packed = pbc_rmessage_integer(options , "packed" , 0 , NULL);
			if (packed) {
				f->label = LABEL_PACKED;
			} else {
				f->label = origin_label; // 这里沿用之前老的模式读出的标签(强制修改前)
				                         // pbc_rmessage_integer只会返回optional/required/repeated
				                         // pbc和protobuf对于packed的信息记录不一样
			}
		}
	}
	f->type_name.n = pbc_rmessage_string(field, "type_name", 0 , NULL) +1;	// abandon prefix '.' 
	int vsz;
	const char * default_value = pbc_rmessage_string(field, "default_value", 0 , &vsz);
	_set_default(pool , f , f->type, default_value , vsz);
}

注释里写得比较清楚了。就不再复述了。

有个题外话,我之前写得转表工具xresloader也很早就接入了proto3,这个工具里已经用proto3了。但是sample里同时提供了proto_v2proto_v3的示例。这个pbc首先是用来读这里的转表工具的转出数据的。当然用老版本的pbc也可以,就是所有的数字得显式指定packed属性。

BTW

因为顺便要给客户端用,之前手动打iOS和android的包麻烦了点。而且有些为了省事是直接工程导入的,自动构建上很麻烦。所以这次干脆写了个基于cmake的一键打包到iOS和Android的静态库或动态库的脚本,放在根目录下build_android.shbuild_ios.sh。如果要编译lua-binding,则需要指定一下lua-5.1或者lua-5.3的包含目录,android的动态库还需要指定下客户端所使用的lua库目录,反正所有都写在README.md里了。

最后,所有完成的修改都放在了 https://github.com/owent-contrib/pbc/tree/proto_v3 里。这个适配只是做了兼容性适配,最好当然还是实现那些proto3的新数据结构啦。而且这个proto_v3的分支我并没有创建PR推回去。但是前面提到的Android和iOS脚本我Push回去了,云风Merge了第一版,第二版暂时还没Merge。第二版只不过是环境检测和兼容性上的一些优化罢了。