前言
GRPC的Protobuf学习笔记
注释
指定Protobuf版本
定义包名
定义选项
github.com/<author>/<repository>
:以当前mod的包名为基准
<repository>/<dir>
:Protobuf相对于当前mod根目录的存放路径
<alias_name>
:Protobuf的别名
1
| option go_package="github.com/<author>/<repository>/<dir>;<alias_name>";
|
定义结构体
定义基本类型
1 2 3 4 5
| message 结构体名 { string 字段名 = 1; int32 字段名 = 2; bool 字段名 = 3; }
|
定义切片
1 2 3
| message 结构体名 { repeated string 字段名 = 1; }
|
定义映射
1 2 3
| message 结构体名 { map <string, string> 字段名 = 1; }
|
定义结构体嵌套
1 2 3 4 5 6
| message 结构体名1 { message 结构体名2 { 数据类型 字段名 = 1; } 结构体名2 数据类型 字段名 = 2; }
|
定义枚举
1 2 3 4 5 6 7
| message 结构体名 { enum Sex { male = 0; female = 1; } Sex 字段名 = 1; }
|
允许多个值相同的枚举
1 2 3 4 5 6 7 8 9
| message 结构体名 { enum Sex { option allow_alias = true; male = 0; female = 1; girl = 1; } Sex 字段名 = 1; }
|
定义OneOf
1 2 3 4 5 6
| message 结构体名 { oneof OneOf名 { string 字段名1 = 1; string 字段名2 = 2; } }
|
设置字段为保留字
通过字段名设置字段为保留字
保留多个
1
| reserved "字段名1", "字段名2";
|
通过唯一标识设置字段为保留字
引入其他Protobuf
1
| import "<dir>/<file>.proto";
|
调用引入的其他Protobuf
1 2 3
| message 结构体名 { <package_name>.结构体名 字段名 = 1 }
|
定义服务
即刻响应的服务
1 2 3
| service 服务名 { rpc 函数名(结构体名) returns (结构体名); }
|
入参为流的服务
1 2 3
| service 服务名 { rpc 函数名(stream 结构体名) returns (结构体名); }
|
出参为流的服务
1 2 3
| service 服务名 { rpc 函数名(结构体名) returns (stream 结构体名); }
|
出入参都为流的服务
1 2 3
| service 服务名 { rpc 函数名(stream 结构体名) returns (stream 结构体名); }
|
编译Protobuf
1
| protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative <dir>/<file>.proto
|
调用服务
即刻响应的服务
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package main
import ( "context" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" "net" )
type TestService struct { test.UnimplementedTestServiceServer }
func (*TestService) Test(context context.Context, req *test.Req) (*test.Res, error) { return &test.Res{Message: req.GetMessage()}, nil }
func main() { listen, _ := net.Listen("tcp", "0.0.0.0:8080") server := grpc.NewServer() test.RegisterTestServiceServer(server, &TestService{}) server.Serve(listen) }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package main
import ( "context" "fmt" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" )
func main() { listen, _ := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure()) client := test.NewTestServiceClient(listen) res, _ := client.Test(context.Background(), &test.Req{Message: ""}) fmt.Println(res) }
|
入参为流的服务
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package main
import ( "context" "fmt" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" "net" )
type TestService struct { test.UnimplementedTestServiceServer }
func (*TestService) TestIn(server test.TestService_TestInServer) error { for { req, err := server.Recv() if err != nil { server.SendAndClose(&test.Res{Message: "EOF"}) break } fmt.Println(req) } return nil }
func main() { listen, _ := net.Listen("tcp", "0.0.0.0:8080") server := grpc.NewServer() test.RegisterTestServiceServer(server, &TestService{}) server.Serve(listen) }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package main
import ( "context" "fmt" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" )
func main() { listen, _ := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure()) client := test.NewTestServiceClient(listen) c, _ := client.TestIn(context.Background()) c.Send(&test.Req{Message: ""}) c.Send(&test.Req{Message: ""}) c.Send(&test.Req{Message: ""}) res, _ := c.CloseAndRecv() fmt.Println(res) }
|
出参为流的服务
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package main
import ( "context" "fmt" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" "net" )
type TestService struct { test.UnimplementedTestServiceServer }
func (*TestService) TestOut(req *test.Req, server test.TestService_TestOutServer) error { server.Send(&test.Res{Message: req.GetMessage()}) server.Send(&test.Res{Message: req.GetMessage()}) server.Send(&test.Res{Message: req.GetMessage()}) return nil }
func main() { listen, _ := net.Listen("tcp", "0.0.0.0:8080") server := grpc.NewServer() test.RegisterTestServiceServer(server, &TestService{}) server.Serve(listen) }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package main
import ( "context" "fmt" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" )
func main() { listen, _ := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure()) client := test.NewTestServiceClient(listen) c, _ := client.TestOut(context.Background(), &test.Req{Message: ""}) for { res, err := c.Recv() fmt.Println(res) if err != nil { break } } }
|
出入参都为流的服务
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package main
import ( "context" "fmt" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" "net" )
type TestService struct { test.UnimplementedTestServiceServer }
func (*TestService) TestIO(server test.TestService_TestIOServer) error { channel := make(chan string) go func() { for { res, err := server.Recv() if err != nil { channel <- "EOF" } channel <- res.GetMessage() } }() for { c := <-channel if c == "EOF" { break } server.Send(&test.Res{Message: ""}) } return nil }
func main() { listen, _ := net.Listen("tcp", "0.0.0.0:8080") server := grpc.NewServer() test.RegisterTestServiceServer(server, &TestService{}) server.Serve(listen) }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package main
import ( "context" "fmt" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" "sync" )
func main() { listen, _ := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure()) client := test.NewTestServiceClient(listen) c, _ := client.TestIO(context.Background()) var waitGroup = sync.WaitGroup{} waitGroup.Add(2) go func() { for { err := c.Send(&test.Req{Message: ""}) if err != nil { waitGroup.Done() break } } }() go func() { for { res, err := c.Recv() if err != nil { waitGroup.Done() break } fmt.Println(res) } }() waitGroup.Wait() }
|
完成
参考文献
哔哩哔哩——go圈里最会写js的奇淼