[go-每日一库] golang-grpc库-protoc基本参数与简单实践(一)
作者:互联网
grpc使用protobuf进行序列化、反序列化,通常用protoc作为编译工具,对于go使用grpc作为rpc的框架,由于protoc工具未实现go-generate,我们需要使用protoc-gen-go插件帮我们生成go文件。
本文的分享分为以下方面:
- 准备工作
- protoc工具的相关命令
- proto文件的定义
- go-grpc的实践
1.准备工作
用go实现grpc的编码,首先下载protoc和protoc-gen-go工具插件。
protoc
官方下载地址:https://github.com/google/protobuf/releases
根据自己的操作系统选择对应版本下载后解压,另外记得设置环境变量:
如果是win平台,直接解压,然后编辑环境变量,add一下即可。
如果是linux平台,编辑/etc/profile,加入解压后的protoc的文件夹,最后source后就可以了。
安装后验证:
protoc --version
libprotoc 3.19.4
protoc-gen-go
命令行下载:
$ go get google.golang.org/protobuf/cmd/protoc-gen-go@latest
$ go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
2.protoc命令参数
受限篇幅,命令参数仅针对常用参数,-I[--proto_path]
,xx_out
。
-I/--proto_path
指定导入的proto文件的路径,如-I
,我们可以用-I.
,指定本文件夹下的proto文件,如果是proto_path,如--proto_path=$PATH
即可。
XX_out
该参数指定protoc工具生成对应编程语言的service文件,如go_out
,在使用时--go_out=plugins=grpc:.
,即指明grpc的插件,本文件夹下。
3.proto文件的定义
首先看个usage:
syntax = "proto3"; // version
package demo; // pkg name
option go_package = "./"; // 注意包名, client、server should import pkg
// define request body
message helloRequest {
string name = 1; // arg-1, type: string, field: name
int64 id = 2; // arg-2, type: int64, field: id
}
// define response body
message helloResponse {
string resp = 1; // arg-1, type: string, field: resp
}
// define service
service helloService {
rpc hello(helloRequest) returns (helloResponse) {} // rpc service, func: hello, params: helloRequest, return helloResponse
}
syntax
指明protoc的版本
package
指明pkg名,用以取分不同的serivce文件,也指定当前的proto文件属于那个包
options
指定编译后的文件的输出目录
message
定义参数
service
定义服务名
接着看看在定义参数的一些注意事项:
支持的数据类型
复杂数据类型
定义List列表(值可以是普通变量,也可以复杂对象):
message ComplexObject {
repeated string sons = 4; // List列表
repeated Result result = 6; // 复杂的对象List
}
// 定义一个新的对象
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
定义枚举成员:
message ComplexObject {
...
Gender gender = 5; // Enum值
...
}
enum Gender {
MAN = 0;
WOMAN = 1;
}
定义Any对象(用于定义任意的值):
message ComplexObject {
repeated google.protobuf.Any any = 7; // Any对象
}
定义Map对象(key,value都可以是复杂对象):
message ComplexObject {
map<string, MapVaule> map = 8; // 定义Map对象
}
// 定义Map的value值
message MapVaule {
string mapValue = 1;
}
通过 reserved保留 Assigning Tags和filed name用于将来扩展用:
message ComplexObject {
reserved 12, 15, 9 to 11; // 预留将来使用的Assigning Tags,
reserved "foo", "bar"; // 预留将来使用的filed name
}
4.protoc的实践
c/s目录结构
proto文件
syntax = "proto3"; // version
package demo; // pkg name
option go_package = "./"; // 注意包名, client、server should import pkg
// define request body
message helloRequest {
string name = 1; // arg-1, type: string, field: name
int64 id = 2; // arg-2, type: int64, field: id
}
// define response body
message helloResponse {
string resp = 1; // arg-1, type: string, field: resp
}
// define service
service helloService {
rpc hello(helloRequest) returns (helloResponse) {} // rpc service, func: hello, params: helloRequest, return helloResponse
}
生成service文件
进入proto目录:
protoc -I. --go_out=plugins=grpc:. hello.proto
go.mod
module demo
go 1.16
replace (
../go-grpc-v1 => ../demo
)
require (
google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.28.0
)
server
package main
import (
"context"
hellopb "demo/proto"
"fmt"
"google.golang.org/grpc"
"log"
"net"
)
const (
ADDR string = "localhost:50052"
)
func main() {
log.Println("grpc server is up...")
lis, err := net.Listen("tcp", ADDR)
if err != nil {
log.Fatal(err.Error())
}
s := grpc.NewServer()
hellopb.RegisterHelloServiceServer(s, &Service{})
err = s.Serve(lis)
if err != nil {
log.Fatal(err.Error())
}
}
type Service struct {}
func (s *Service) Hello(ctx context.Context, req *hellopb.HelloRequest) (*hellopb.HelloResponse, error) {
fmt.Printf("receive request, params -> name: %s, id: %d\n", req.Name, req.Id)
return &hellopb.HelloResponse{
Resp: fmt.Sprintf("resp from server, name: %s, id: %d", req.GetName(), req.GetId()),
}, nil
}
client
package main
import (
"context"
hellopb "demo/proto"
"fmt"
"google.golang.org/grpc"
"log"
)
func main() {
conn, err := grpc.Dial("localhost:50052", grpc.WithInsecure()) // conn rpc server
if err != nil {
log.Fatal(err.Error())
}
defer conn.Close()
client := hellopb.NewHelloServiceClient(conn) // new a client
resp, err := client.Hello(context.Background(), &hellopb.HelloRequest{Name: "Bob", Id: 1000}) // send request, receive response
if err != nil {
log.Fatal(err.Error())
}
fmt.Println(resp.Resp)
}
最后先跑server,再跑client,即完成c/s的grpc的简单实践。
参考:
标签:protoc,string,err,proto,grpc,golang,go 来源: https://www.cnblogs.com/davis12/p/16503010.html