什麼是protobuf
資料在進行網路傳輸的時候,需要進行序列化,序列化協議有很多種,比如xml, json,protobuf等
gRPC預設使用protocol buffers,這是google開源的一套成熟的結構資料序列化機制。
簡單使用
定義一種原始檔,副檔名為 .proto
,使用這種原始檔,可以定義儲存類的內容(訊息型別)。
protobuf有自己的編譯器 protoc
,可以將 .proto
編譯成對應語言的檔案,就可以進行使用了。
工具安裝
brew install protobuf
get github.com/golang/protobuf/protoc-gen-go
檔案建立
// 指定的當前proto語法的版本,有2和3
syntax = "proto3";
//option go_package = "path;name"; path 表示生成的go檔案的存放地址,會自動生成目錄的
// name 表示生成的go檔案所屬的包名
option go_package="/service";
// 指定等會檔案生成出來的package
package service;
message User {
string username = 1;
int32 age = 2;
}
使用命令生成對應的GO檔案
protoc --go_out=. user.proto
程式碼使用
package main
import (
"clinet/service"
"fmt" "google.golang.org/protobuf/proto")
func main() {
user := &service.User{
Username: "mszlu",
Age: 20,
}
//轉換為protobuf
marshal, err := proto.Marshal(user) //將這個 User 物件編碼為 Protobuf 格式的位元組陣列 ([]byte)。
if err != nil {
panic(err)
}
newUser := &service.User{}
err = proto.Unmarshal(marshal, newUser)//將位元組陣列解碼回 User 物件
if err != nil {
panic(err)
}
fmt.Println(newUser.String())
}
proto檔案介紹
message使用
一個訊息型別是透過關鍵字message欄位指定的。
message User {
string username = 1;
int32 age = 2;
}
欄位規則
- required string name = 1;
這個欄位是必填的,意味著在建立和序列化 Person 訊息時,必須設定 name 欄位的值。否則會報錯。在 Go 中,這個欄位會被生成為 string 型別。 - optional int32 age = 2;
這個欄位是可選的,意味著在建立和序列化 Person 訊息時,可以不設定 age 欄位。如果不設定,則會使用該欄位型別的預設值,在這裡是 0。在 Go 中,這個欄位會被生成為 int32 型別。 - repeated string phoneNumbers = 3;
這個欄位是可重複的,意味著一個 Person 訊息可以有多個電話號碼。在序列化和反序列化過程中,這些電話號碼的順序會被保留。在 Go 中,這個欄位會被生成為 []string 型別的切片。
message Person {
required string name = 1;
optional int32 age = 2;
repeated string phoneNumbers = 3;
}
// 建立一個 Person 訊息
person := &Person{
Name: "Alice",
Age: 30,
PhoneNumbers: []string{"123-456-7890", "987-654-3210"},
}
// 序列化為 Protobuf 二進位制資料
data, err := proto.Marshal(person)
if err != nil {
// 處理錯誤
}
// 反序列化回 Person 物件
newPerson := &Person{}
err = proto.Unmarshal(data, newPerson)
if err != nil {
// 處理錯誤
}
// 輸出反序列化後的 Person 物件
fmt.Println(newPerson)
標識號
在訊息體的定義中,每個欄位都必須要有一個唯一的標識號,標識號是[0,2^29-1]範圍內的一個整數。
message Person {
string name = 1; // (位置1)
int32 id = 2;
optional string email = 3;
repeated string phones = 4; // (位置4)
}
訊息複雜使用
message PersonInfo {
message Person {
string name = 1;
int32 height = 2;
repeated int32 weight = 3;
}
repeated Person info = 1;
}
如果你想在它的父訊息型別的外部重用這個訊息型別,你需要以PersonInfo.Person的形式使用它,如:
message PersonMessage {
PersonInfo.Person info = 1;
}
定義服務
如果想要將訊息型別用在RPC系統中,可以在.proto檔案中定義一個RPC服務介面,protocol buffer 編譯器將會根據所選擇的不同語言生成服務介面程式碼及存根。
service SearchService {
//rpc 服務的函式名 (傳入引數)返回(返回引數)
rpc Search (SearchRequest) returns (SearchResponse);
}
上述代表表示,定義了一個RPC服務,該方法接收SearchRequest返回SearchResponse
service MyService {
rpc GetUser(GetUserRequest) returns (GetUserResponse);
rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse);
}
message GetUserRequest {
string userId = 1;
}
message GetUserResponse {
User user = 1;
}
message UpdateUserRequest {
User user = 1;
}
message UpdateUserResponse {
bool success = 1;
}
message User {
string name = 1;
int32 age = 2;
}
MyService 是一個服務,它定義了兩個 RPC 方法:
- GetUser: 輸入一個 GetUserRequest,返回一個 GetUserResponse。
- UpdateUser: 輸入一個 UpdateUserRequest,返回一個 UpdateUserResponse。
參考文章
https://mszlu.com/grpc/01/01.html#_3-3-proto檔案介紹