Protocol Buffers 是由 Google 所推出的一格式(後台真硬),你可以把它想像成是 XML 或 JSON 格式,但是更小、更快,而且更簡潔。這能夠幫你節省網路與硬體資源,且你只需要定義一次資料結構,接著就會自動生成符合你程式語言的檔案,讓你能夠直接在你的程式上使用。

而且有趣的是一但你定義了資料結構,你就能在多個語言上使用,像是 C++C#GoJavaPythonJavaScript⋯等,如此一來就不用像 JSON 那樣到不同語言時還要重新定義資料結構。

結構就是文件

首先在傳遞資料前,我們需要定義資料結構。這些檔案以 .proto 作為後輟,有趣的是這些檔案本身就是結構定義檔,所以就不用額外撰寫 API 文件,因為 .proto 檔本身就是一種「文件」。

// 撰寫格式是 Proto v3。
syntax = "proto3"; // User 帶有使用者資料,如帳號、密碼。
message User {
string username = 1;
string password = 2;
} // Post 帶有文章資料。
message Post {
int64 id = 1;
string content = 2;
}

在 Protocol Buffers 中會需要定義資料型態,這讓你明白你應該要傳入什麼類型的資料,這些資料型態可以在這個頁面找到。

後面的數字是什麼?

你可能會好奇為什麼我們需要在每個欄位後面標註數字,實際上這是 Protocol Buffers 編碼與解碼所會用到的編號,這令你能夠移除其中一個欄位而不打亂整個資料結構的編碼與解碼(除非你更改了數字編號)。

與 JSON 比較?

與 JSON 比較,Protocol Buffers 有這些優點。

message User {
string username = 1;
string password = 2;
}
  • 資料輕量化:資料非常輕量,省去了不必要的 { 或 : 累贅。
  • 混淆性:在一般人眼中無法輕易地猜測出資料結構為何,因為有經過編碼。
  • 效能高:處理速度很快。
  • 極具方便性:結構就是你的資料模型,你能夠直接在程式中使用這些結構,而不用建立新的物件來接納、映射(Mapping)這些資料。
  • 清晰明瞭、無需文件:.proto 檔案本身就是你的文件,不需要額外撰寫 API 或結構文件來告訴別人你接受怎樣的資料。

在行動裝置的應用程式、伺服器與伺服器之間的通訊,或是單頁應用程式都可以用上 Protocol Buffers。

什麼時候應該繼續用 JSON?

當然也不是一味地拋棄 JSON,在有些時候 Protocol Buffers 仍然沒有 JSON 要來地方便。

{
"username": "Yami Odymel",
"password": "test"
}
  • 當你希望資料是人類可解讀的時候。
  • 你不打算直接把接收到的資料拿來處理,你希望從中拿取部分資料作為處理。
  • 你希望在純文字、終端機的情況下就能夠與伺服器溝通。
  • 不想經過任何特殊處理,想直接在瀏覽器中解讀。

在傳統網站、小型網站中仍可使用 JSON 作為資料傳遞的格式,如果此時用上 Protocol Buffers 可能會花費過多的時間與開發成本。

傳遞的內容看起來怎樣?

下面這張圖解釋了 Protocol Buffers 傳遞的資料格式。

(圖片來源:https://martin.kleppmann.com/2012/12/05/schema-evolution-in-avro-protocol-buffers-thrift.html)

以最下面的範例結果作為例子,這是 Protocol Buffers 傳遞的內容。Protocol Buffers 位元陣列:

[8 185 96 18 11 89 97 109 105 32 79 100 121 109 101 108 26 4 116 101 115 116]

Protocol Buffers 位元陣列轉為字串:

�`
Yami Odymeltest

解譯成人類可讀:

12345   Yami Odymel   test

比起 JSON 的 { 與 : 要來得更加簡潔,並且傳輸時的容量又更小了。


1. 安裝 Protocol Buffers 生成工具

首先需要安裝 protoc,這是用來將 .proto 檔案轉化為程式的工具。先到 Protobuf 的 GitHub 釋出頁面

滾到最下面,下載符合自己系統的已編譯版本,如此一來就不用再手動編譯。

下載之後解壓縮,然後將 bin/protoc 檔案丟至系統路徑 $PATH,這樣我們就能夠在終端機執行。

2. 安裝 Golang 擴充插件

接下來的教學會以 Golang 為主,其他語言可能要自行參考這裡,首先以 go get 取得 protoc-gen-go

$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

這是 protoc 的擴充插件,能夠將程式轉化成 Golang 語言。

接著進到 $GOPATH/bin 中會找到我們剛才下載的 protoc-gen-go 檔案,同樣地,將他丟進系統路徑 $PATH,如此一來才能在稍後於終端機內執行。

3. 轉化 Proto 文件

接著我們要將 .proto 轉化成 Golang 程式才能夠在 Golang 中使用,現在新增下列文件,並且將其命名為 example.proto

// 撰寫格式是 Proto v3。
syntax = "proto3";
// 生成的程式在 Golang 中將會屬於 `protobuf` 套件。
package protobuf; // User 帶有使用者資料,如帳號、密碼。
message User {
int64 id = 1;
string username = 2;
string password = 3;
}

然後透過下列指令將 .proto 轉化成 Golang 程式。

$ protoc --go_out=. *.proto

然後我們就能得到一個屬於 protobuf 套件的 example.pb.go 檔案,內容大略如下。

現在我們就可以在 Golang 中開始使用這個結構。

4. 解碼與編碼

記得將我們剛才的 example.pb.go 放至 /protobuf 資料夾內(自行手動新增),因為那個檔案屬於 protobuf 套件。

現在我們要透過這些結構來解碼、與編碼資料(注意:下列範例為了簡潔,都忽略了錯誤處理,這是很不好的行為)。

package main

import (
"fmt" "./protobuf"
"github.com/gogo/protobuf/proto"
) func main() {
// 建立一個 User 格式,並在其中放入資料。
data := protobuf.User{
Id: 12345,
Username: "Yami Odymel",
Password: "test",
} // 將資料編碼成 Protocol Buffer 格式(請注意是傳入 Pointer)。
dataBuffer, _ := proto.Marshal(&data) // 將已經編碼的資料解碼成 protobuf.User 格式。
var user protobuf.User
proto.Unmarshal(dataBuffer, &user) // 輸出解碼結果。
fmt.Println(user.Id, " ", user.Username, " ", user.Password)
}

透過下列指令執行。

$ go run main.go

接著我們就能夠得到這樣的結果。

12345   Yami Odymel   test

上面這個結果是由資料編碼成 Protocol Buffers 然後解碼所得到的。

from: https://yami.io/protobuf/

比起 JSON 更方便、更快速、更簡短的 Protobuf 格式的更多相关文章

  1. Groovy系列-groovy比起Java--有哪些地方写起来更舒服?

    groovy比起java-有哪些地方写起来更舒服 java发展缓慢,语法落后冗余 说起java,其实java挺好的,java现在的性能也不错,但是,java的语法显然比较落后,而且冗余,getter/ ...

  2. 玩转 .NET Core 3.0:逐浪CMS新版发布,建站更简单、网站更安全

    2019年11月11日,在大家都忙于网上体会“双11 ”的热闹气氛的时候,逐浪CMS开发者团队正在做着新版本发布的最后工作.此次更新是基本于 .NET Core 3.0开发,也是全国首个基于 .NET ...

  3. .NET 事件总线,简化项目、类库、线程、服务等之间的通信,代码更少,质量更好。‎

    Jaina .NET 事件总线,简化项目.类库.线程.服务等之间的通信,代码更少,质量更好.‎ 安装 Package Manager Install-Package Jaina .NET CLI do ...

  4. Quality Over Quantity: 更少一些,更好一些_第1页_福布斯中文网

    Quality Over Quantity: 更少一些,更好一些_第1页_福布斯中文网     Quality Over Quantity: 更少一些,更好一些    2013年04月09日     ...

  5. graphicview和widgets没本质区别。它只是更轻量级,更灵活,性能更高的widgets

    graphicview和widgets没本质区别.它只是更轻量级,更灵活,性能更高的widgets.核心就是把widgets变成了更轻量级的graphicitem,把QWidget的各种事件转换成了g ...

  6. IntelliJ IDEA 2019.2最新解读:性能更好,体验更优,细节处理更完美!

    idea 2019.2 准备 idea 2019.2正式版是在2019年7月24号发布的,本篇文章,我将根据官方博客以及自己的理解来进行说明,总体就是:性能更好,体验更优,细节处理更完美! 支持jdk ...

  7. vue3.0和2.0的区别,Vue-cli3.0于 8月11日正式发布,更快、更小、更易维护、更易于原生、让开发者更轻松

    vue3.0和2.0的区别Vue-cli3.0于 8月11日正式发布,看了下评论,兼容性不是很好,命令有不少变化,不是特别的乐观vue3.0 的发布与 vue2.0 相比,优势主要体现在:更快.更小. ...

  8. Nvidia发布更快、功耗更低的新一代图形加速卡

    导读 不出意外的,Nvidia在其举行的Supercomputing 19大会上公布了很多新闻,这些我们将稍后提到.但被忽略的一条或许是其中最有趣的:一张更快.功耗更低的新一代图形加速卡. 多名与会者 ...

  9. 会议更流畅,表情更生动!视频生成编码 VS 国际最新 VVC 标准

    阿里云视频云的标准与实现团队与香港城市大学联合开发了基于 AI 生成的人脸视频压缩体系,相比于 VVC 标准,两者质量相当时可以取得 40%-65% 的码率节省,旨在用最前沿的技术,普惠视频通话.视频 ...

随机推荐

  1. 【记录】url 中出现特殊字符该怎么办

    url中出现特殊字符+ URL 中+号表示空格 %2B 空格 URL中的空格可以用+号或者编码 %20/ 分隔目录和子目录 %2F ? 分隔实际的URL和参数 %3F % 指定特殊字符 %25 # 表 ...

  2. Python监控目录和文件变化

    一.os.listdir import os, time path_to_watch = "." before = dict ([(f, None) for f in os.lis ...

  3. 递归与分治策略之循环赛日程表Java实现

    递归与分治策略之循环赛日程表 一.问题描述 设有n=2^k个运动员要进行网球循环赛.现要设计一个满足以下要求的比赛日程表: (1)每个选手必须与其他n-1个选手各赛一次: (2)每个选手一天只能参赛一 ...

  4. luoguP4555 [国家集训队]最长双回文串 manacher算法

    不算很难的一道题吧.... 很容易想到枚举断点,之后需要处理出以$i$为开头的最长回文串的长度和以$i$为结尾的最长回文串的长度 分别记为$L[i]$和$R[i]$ 由于求$R[i]$相当于把$L[i ...

  5. bzoj4641 基因改造 KMP / hash

    依稀记得,$NOIP$之前的我是如此的弱小.... 完全不会$KMP$的写法,只会暴力$hash$.... 大体思路为把一个串的哈希值拆成$26$个字母的位权 即$hash(S) = \sum\lim ...

  6. LOJ P3960 列队 树状数组 vector

    https://www.luogu.org/problemnew/show/P3960 树状数组预处理之后直接搞就可以了,也不是很好解释,反正就是一个模拟过程的暴力用树状数组维护,还挺巧妙的. 我为什 ...

  7. Linux下gcc与g++用法以及编写makefile

    1.         gcc与g++编译流程: 1)         编译流程: 2)         预处理:生成.i的预处理文件. Ø 只激活预处理,这个不生成文件,需要把它重定向一个输出文件. ...

  8. hdu 5317 RGCDQ (2015多校第三场第2题)素数打表+前缀和相减求后缀(DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5317 题意:F(x) 表示x的不同质因子的个数结果是求L,R区间中最大的gcd( F(i) , F(j ...

  9. 【原】MyBatis执行DDL:create table,drop table等等

    [前言] 对MyBatis一直停留在仅仅会用的阶段,常用的场景就是通过MyBatis对表数据进行DML(insert, delete, update等)操作,从来没有想过通过MyBatis对数据库 进 ...

  10. j.u.c系列(01) ---初探ThreadPoolExecutor线程池

    写在前面 之前探索tomcat7启动的过程中,使用了线程池(ThreadPoolExecutor)的技术 public void createExecutor() { internalExecutor ...