安装gRPC核心库
go get google.golang.org/grpc
安装protoc编译器
安装protoc代码生成工具
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
安装成功后后在$GOPATH/bin目录下会出现protoc-gen-go.exe 和protoc-gen-go-grpc.exe
使用protoc
新建.proto文件
在protoc包下新建hello.proto,内容如下:
// 申明使用proto3语法
syntax = "proto3";
// 表示最后生成的go文件放在哪个目录哪个包下,
// .表示在当前目录生成, service表示生成的go文件包名是service
option go_package = "../service;service";
// 申明一个service, 有个一个SayHello 的方法,
// 该方法的参数为HelloRequest, 返回值是HelloResponse
// 用关键词rpc修饰
service HelloService {
rpc SayHello(HelloRequest) returns( HelloResponse) {}
}
// 定义结构体HelloRequest,表示SayHello接口请求参数
// 用message关键词修饰
message HelloRequest {
// 参数定义, 1,2仅表示参数的顺序, 不是赋值
string name = 1;
string msg = 2;
}
// 定义结构体HelloResonse, 表示SayHello接口的返回值
message HelloResponse {
string msg = 1;
}
使用protoc编译器
使用protoc编译器, 根据.proto文件自动生成grpc代码
cd proto && protoc --go-grpc_out=. --go_out=. hello.proto
执行成功后, 会在service目录下,出现hello.pb.go 和 hello_grpc.pb.go 两个文件
grpc 服务端
- 重写SayHello方法
import (
"context"
"fmt"
hello "go-grpc-demo/api/service"
"net"
"google.golang.org/grpc"
)
type helloService struct {
hello.UnimplementedHelloServiceServer
}
func (c *helloService) SayHello(ctx context.Context, in *hello.HelloRequest) (*hello.HelloResponse, error) {
return &hello.HelloResponse{Msg: "hello " + in.Name + "!" + in.Msg}, nil
}
- 开启端口
server, err := net.Listen("0.0.0.0", "9999")
- 创建gRPC服务器
grpcServer := grpc.NewServer()
- 将service注册到gRPC服务器中
hello.RegisterHelloServiceServer(grpcServer, &helloService{})
- 开启gRPC服务器
err := grpcServer.Serve(server)
grpc 客户端访问
- 建立tcp连接
// 新建grpc连接, 不加安全校验
conn, err := grpc.Dial("127.0.0.1:9999", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
fmt.Printf("start grpc client error.%v", err)
return
}
defer conn.Close()
- 建立grpc客户端
// 创建grpc客户端
client := hello.NewHelloServiceClient(conn)
- 调用函数
// 尝试调用服务端函数
res, err := client.SayHello(context.Background(), &hello.HelloRequest{Name: "Tom", Msg: "First"})
if err != nil {
fmt.Printf("call sayHello method error,%v", err)
}
fmt.Println(res.GetMsg())
增加安全校验(基于token)
- 创建结构体, 实现PerRPCCredentials接口
package sert
import (
"context"
)
type CustomTokenAuth struct{}
func (c CustomTokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"appId": "demo",
"appKey": "123456",
}, nil
}
// 是否开启TSL认证
func (c CustomTokenAuth) RequireTransportSecurity() bool {
return false
}
- 客户端访问时添加认证
var opts []grpc.DialOption
// 不使用TSL
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
// 使用token
opts = append(opts, grpc.WithPerRPCCredentials(new(sert.CustomTokenAuth)))
conn, err := grpc.Dial("127.0.0.1:9999", opts...)