[TOC]git
RPC的消息傳輸能夠是TCP,能夠是UDP,也能夠是HTTP,當RPC消息傳輸是HTTP時,它的結構與RESTful的架構相似github
RPC和RESTful有什麼不一樣呢:golang
RPC操做的是方法對象, RESTful操做的是資源json
RPC的客戶端和服務器端是緊耦合的,客戶端須要知道服務端的函數名字,參數類型、順序等,才能遠程過程調用。bash
RESTful基於 http的語義操做資源,參數的順序通常沒有關係服務器
RCP更適合定製化架構
RESTful執行的是對資源的操做,主要都是CURD(增刪改查)的操做,若須要實現一個特定的功能,如計算一個班級的平均分,這個時候使用RPC定義服務器的方法(如:Stu.CalAvg)供客戶端調用則顯得更有意義框架
在gRPC客戶端能夠直接調用不一樣服務器上的遠程程序,使用姿式看起來就像調用本地過程調用同樣,很容易去構建分佈式應用和服務。客戶端和服務端能夠分別使用gRPC支持的不一樣語言實現。tcp
基於HTTP2標準設計,比其餘框架更優的地方有分佈式
長鏈接,雙向流、頭部壓縮、多複用請求
等節省帶寬
、下降TCP連接次數
、節省CPU使用
和延長電池壽命
請求應答式
客戶端發出一次請求,能夠從服務端讀取一系列的消息
客戶端寫一系列消息給到服務端,等待服務端應答
客戶端和服務端均可以經過讀寫數據流來發送一系列消息
protobuf 是一個對數據序列化的方式,相似的有JSON,XML等
Message命名採用駝峯命名方式,字段是小寫加下劃線
message ServerRequest { required string my_name = 1; }
Enums類型名採用駝峯命名方式,字段命名採用大寫字母加下劃線
enum MyNum { VALUE1 = 1; VALUE2 = 2; }
Service與rpc方法名統一採用駝峯式命名
service Love { // 定義Confession方法 rpc MyConfession(Request) returns (Response) {} }
關於prtobuf的安裝能夠看看以前寫的一個安裝步驟《5個步驟搞定PROTOBUF的安裝》
在proto文件中使用package
關鍵字聲明包名,默認轉換成go中的包名與此一致,能夠自定義包名,修改go_package
便可:
test.proto
syntax = "proto3"; // proto版本 package pb; // 指定包名,默認go中包名也是這個 // 定義Love服務 service Love { // 定義Confession方法 rpc Confession(Request) returns (Response) {} } // 請求 message Request { string name = 1; } // 響應 message Response { string result = 1; }
安裝好protoc環境以後,進入到proto文件的目錄下,(例如打開window git
)執行以下命令,將proto
文件編譯成pb.go
文件
protoc --go_out=plugins=grpc:. test.proto
轉換結果:
// Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 // protoc v3.13.0 // source: test.proto package test import ( context "context" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 type Request struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } type Response struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Result string `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` } // LoveServer is the server API for Love service. type LoveServer interface { Confession(context.Context, *Request) (*Response, error) }
目錄結構爲:
------------------------------- | mygrpc | ---------pb | -------------test.proto | ---------client.go | ---------srv.go -------------------------------
client.go
package main import ( "context" "log" "mygrpc.com/pb" "google.golang.org/grpc" ) func main() { // 鏈接grpc服務 conn, err := grpc.Dial(":8888", grpc.WithInsecure()) if err != nil { log.Fatal(err) } // 很關鍵 defer conn.Close() // 初始化客戶端 c := pb.NewLoveClient(conn) // 發起請求 response, err := c.Confession(context.Background(), &pb.Request{Name: "小魔童哪吒"}) if err != nil { log.Fatal(err) } log.Println(response.Result) }
server.go
package main import ( "context" "log" "net" "google.golang.org/grpc" "mygrpc.com/pb" ) // 定義Love服務 type Love struct { } // 實現Love服務接口 func (l *Love) Confession(ctx context.Context, request *pb.Request) (*pb.Response, error) { resp := &pb.Response{} resp.Result = "your name is " + request.Name return resp, nil } func main() { // 監聽8888端口 listen, err := net.Listen("tcp", ":8888") if err != nil { log.Fatal(err) } // 實例化grpc server s := grpc.NewServer() // 註冊Love服務 pb.RegisterLoveServer(s, new(Love)) log.Println("Listen on 127.0.0.1:8888...") s.Serve(listen) }
下一次介紹關於gRPC的認證
技術是開放的,咱們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。
我是小魔童哪吒,歡迎點贊關注收藏,下次見~