go grpc(protobuf) 簡(jiǎn)單使用教程

go gprc 使用 教程

技術(shù)棧

grpc
go
protobuff

1.環(huán)境

1.1. 安裝protoc

項(xiàng)目地址 https://github.com/protocolbuffers/protobuf

下載protobuff, 有條件的github上直接下載,github下載地址锐膜,或者可以從maven倉庫下載

在maven倉庫中找到對(duì)應(yīng)的版本,進(jìn)行下載瑟慈,linux ,windows 都有

1589089027209.png

這里我下載 windows 64 位的這個(gè)

下載下來的是可執(zhí)行文件,直接放到環(huán)境變量里面且改,這個(gè)文件名太長(zhǎng)了浦辨,把后綴都去掉

我放的路徑 %GOPATH%\bin\protoc.exe

1.2. 安裝 protoc-gen-go

直接go get -u github.com/golang/protobuf/protoc-gen-go

go get 的比較慢的話可以用代理。需要配置下代理伊诵。

看下 %GOPATH%\bin\ 有沒有protoc-gen-go.exe ,沒有的話需要找到下載的包進(jìn)行安裝回官。

下載目錄在:%GOPATH%\pkg\mod\github.com\golang\protobuf@xxx\protoc-gen-go

進(jìn)入目錄然后 go install 曹宴,然后再去看bin 目錄就會(huì)生成protoc-gen-go.exe

1589090845985.png

2. 建項(xiàng)目實(shí)踐

1. 建目錄 grpcprj

go mod init grpcprj

這個(gè)是我創(chuàng)建后的目錄

|   go.mod #工程文件
|   go.sum #工程文件
+---client #客戶端代碼存放目錄
|       main.go 
+---proto #proto 文件存放目錄,包括通過protoc 編譯后的文件
|   \---hello
|           hello.pb.go #protoc 根據(jù)proto文件生成的go項(xiàng)目文件
|           hello.proto #proto 文件
\---server #服務(wù)端代碼
    |   main.go
    \---handler #服務(wù)端接口實(shí)現(xiàn)
            hello.go
2. 編寫proto文件
syntax="proto3"; //版本

package go.rpc.srv.hello; //作用域

service Hello{ //service 表示服務(wù)歉提,在這里面定義接口
 //定義了一個(gè)接口SayHello 接收了一個(gè)Say消息笛坦,返回一個(gè)Say消息
 rpc SayHello(Say) returns (Say);  
}

// 定義一個(gè)結(jié)構(gòu)體,Say
message Say {
string name = 1; // 定義格式如下 :<修飾符> 類型 字段名 = 唯一編號(hào)

//由于一些歷史原因苔巨,基本數(shù)值類型的repeated的字段并沒有被盡可能地高效編碼版扩。
//在新的代碼中,用戶應(yīng)該使用特殊選項(xiàng)[packed=true]來保證更高效的編碼侄泽。
//注意[packed=true]只能用在 repeated修飾的數(shù)字類型中
//repeated用來定義數(shù)組
repeated  int32 list =2; //repeated 

//定義map
map<string, string> maps = 3;

//有時(shí)候你需要保留一些你以后要用到的編號(hào)或者變量名资厉,使用reserved關(guān)鍵字
reserved 3, 15, 9 to 11; //保留 3,15蔬顾,9到11
reserved "foo", "bar";

//string var2 = 3;//編譯會(huì)報(bào)錯(cuò),因?yàn)?被保留了
//string var3 = 10;//編譯會(huì)報(bào)錯(cuò)湘捎,因?yàn)?0被保留了
//string foo = 12;//編譯會(huì)報(bào)錯(cuò)诀豁,因?yàn)閒oo被保留了
}

消息體可以嵌套,也可以引入其他的proto文件

import "google/protobuf/any.proto"; //引入其他文件

//消息嵌套
message ParentBean{
    ChildA child = 1;
    message ChildB{
        string name = 1;
    } 
    ChildB child2 = 2 ;
}
message ChildA{
    string name = 1;
}

字段類型對(duì)比

.proto Type Go Type 說明
double float64
float float32
int32 int32 使用變長(zhǎng)編碼窥妇,對(duì)于負(fù)值的效率很低舷胜,如果你的域有可能有負(fù)值,請(qǐng)使用sint64替代
uint32 uint32 使用變長(zhǎng)編碼
uint64 uint64 使用變長(zhǎng)編碼
sint32 int32 使用變長(zhǎng)編碼,這些編碼在負(fù)值時(shí)比int32高效的多
sint64 int64 使用變長(zhǎng)編碼烹骨,有符號(hào)的整型值翻伺。編碼時(shí)比通常的int64高效。
fixed32 uint32 總是4個(gè)字節(jié)沮焕,如果數(shù)值總是比總是比228大的話吨岭,這個(gè)類型會(huì)比uint32高效。
fixed64 uint64 總是8個(gè)字節(jié)峦树,如果數(shù)值總是比總是比256大的話辣辫,這個(gè)類型會(huì)比uint64高效。
sfixed32 int32 總是4個(gè)字節(jié)
sfixed64 int64 總是8個(gè)字節(jié)
bool bool 默認(rèn) false
string string 一個(gè)字符串必須是UTF-8編碼或者7-bit ASCII編碼的文本魁巩,默認(rèn)值為空急灭。
bytes []byte 默認(rèn)是空數(shù)組
3. 編譯proto文件

? proto 文件編寫完畢以后,使用protoc 進(jìn)行編譯谷遂,編譯成成 xxx.pb.go葬馋,編譯是干什么呢?

protoc --go_out=plugins=grpc:. proto/hello/hello.proto

? 運(yùn)行命令后會(huì)在 proto 文件同目錄生成 xxx.pb.go,對(duì)應(yīng)的service 會(huì)成生成一個(gè)空的實(shí)現(xiàn)(指的是只做了實(shí)現(xiàn)肾扰,并沒有具體業(yè)務(wù)功能)畴嘶,這里需要注意的是,默認(rèn)go環(huán)境變量已經(jīng)配置正確白对,gopath\bin 在環(huán)境變量里面掠廓。

hello.proto(最簡(jiǎn)的)

syntax="proto3";

service Hello{
    rpc SyaHello(Say) returns (Say);
}

message Say {
  string name = 1;
}

編譯后的文件

...省略了其他代碼
// HelloServer is the server API for Hello service.
// helloServer 接口
type HelloServer interface { 
    SyaHello(context.Context, *Say) (*Say, error)
}

// UnimplementedHelloServer can be embedded to have forward compatible implementations.

type UnimplementedHelloServer struct {
}

// 以下是一個(gè)空的實(shí)現(xiàn),沒有實(shí)現(xiàn)任何業(yè)務(wù)邏輯
func (*UnimplementedHelloServer) SyaHello(context.Context, *Say) (*Say, error) {
    return nil, status.Errorf(codes.Unimplemented, "method SyaHello not implemented")
}
4. 實(shí)現(xiàn)服務(wù)端接口邏輯

? 服務(wù)端可以實(shí)現(xiàn)甩恼,也可以不實(shí)現(xiàn)蟀瞧,也可以改下上面的默認(rèn)生成的這個(gè)實(shí)現(xiàn)類,這里重新實(shí)現(xiàn)了下条摸,里面寫自己的業(yè)務(wù)邏輯悦污。

server/handler/hello.go(最簡(jiǎn)實(shí)現(xiàn))

package handler

import (
    "context"
    "fmt"
    h "grpcprj/proto/hello"
    )

type HelloImpl struct {}

func (hi *HelloImpl)SyaHello(ctx context.Context,in *h.Say) (*h.Say, error){
    msg:=fmt.Sprintf("echo say:%s",in.GetName())
    return &h.Say{Name:msg},nil
}
5. 服務(wù)端代碼
package main

import (
 "context"
 "google.golang.org/grpc"
 h "grpcprj/proto/hello"
 "log"
 "time"
)

var(
 addr  ="localhost:8081"
 defmsg = "hello boger"
)

func main()  {

 var(
     conn *grpc.ClientConn
     ctx context.Context
     cancel context.CancelFunc
     err error
     r *h.Say
 )

 if conn,err=grpc.Dial(addr,grpc.WithInsecure(),grpc.WithBlock());err!=nil{
     log.Fatalf("conn server err :%v",err)
 }
 defer conn.Close()
 c := h.NewHelloClient(conn)

 ctx,cancel=context.WithTimeout(context.Background(),time.Second)
 defer cancel()
 if r,err=c.SyaHello(ctx,&h.Say{Name:defmsg});err!=nil{
     log.Fatalf("get error :%v",err)
 }
 log.Printf("get msg :%s",r.Name)
}
6. 客戶端代碼

? protoc 生成的go 代碼里面包括服務(wù)端的定義,和客戶端的定義(協(xié)議的打包钉蒲,解包都包括了)

? grpcprj/client/hello.go

package main

import (
    "context"
    "google.golang.org/grpc"
    h "grpcprj/proto/hello"
    "log"
    "time"
)

var(
    addr  ="localhost:8081"
    defmsg = "hello boger"
)

func main()  {

    var(
        conn *grpc.ClientConn
        ctx context.Context
        cancel context.CancelFunc
        err error
        r *h.Say
    )

    if conn,err=grpc.Dial(addr,grpc.WithInsecure(),grpc.WithBlock());err!=nil{
        log.Fatalf("conn server err :%v",err)
    }
    defer conn.Close()
    c := h.NewHelloClient(conn)

    ctx,cancel=context.WithTimeout(context.Background(),time.Second)
    defer cancel()
    if r,err=c.SyaHello(ctx,&h.Say{Name:defmsg});err!=nil{
        log.Fatalf("get error :%v",err)
    }
    log.Printf("get msg :%s",r.Name)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末切端,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子顷啼,更是在濱河造成了極大的恐慌踏枣,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钙蒙,死亡現(xiàn)場(chǎng)離奇詭異茵瀑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)躬厌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門马昨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事鸿捧∫俾ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵匙奴,是天一觀的道長(zhǎng)堆巧。 經(jīng)常有香客問我,道長(zhǎng)饥脑,這世上最難降的妖魔是什么恳邀? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮灶轰,結(jié)果婚禮上谣沸,老公的妹妹穿的比我還像新娘。我一直安慰自己笋颤,他們只是感情好乳附,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伴澄,像睡著了一般赋除。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上非凌,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天举农,我揣著相機(jī)與錄音,去河邊找鬼敞嗡。 笑死颁糟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喉悴。 我是一名探鬼主播棱貌,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼箕肃!你這毒婦竟也來了婚脱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤勺像,失蹤者是張志新(化名)和其女友劉穎障贸,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吟宦,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡篮洁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了督函。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖辰狡,靈堂內(nèi)的尸體忽然破棺而出锋叨,到底是詐尸還是另有隱情,我是刑警寧澤宛篇,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布娃磺,位于F島的核電站,受9級(jí)特大地震影響叫倍,放射性物質(zhì)發(fā)生泄漏偷卧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一吆倦、第九天 我趴在偏房一處隱蔽的房頂上張望听诸。 院中可真熱鬧,春花似錦蚕泽、人聲如沸晌梨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仔蝌。三九已至,卻和暖如春荒吏,著一層夾襖步出監(jiān)牢的瞬間敛惊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工绰更, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞧挤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓动知,卻偏偏與公主長(zhǎng)得像皿伺,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子盒粮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355