install

grpc在19年后go语言的编译插件改了,原本的– plugins = go的编译插件不能用了,必须使用新的编译插件。

安装相关插件

1
2
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

不出意外这些插件会出现在**$(GOPATH)**里面,但是不知道为什么我的GOPATH不起作用,后面把相关插件移动到了

1
/usr/local/bin

一般而言GOPATH在home/go这个路径。

安装grpc

1
brew install grpc
1
2
3
4
5
cd /usr/local/Cellar/grpc/1.41.0/bin
ls
grpc_cli grpc_node_plugin grpc_python_plugin
grpc_cpp_plugin grpc_objective_c_plugin grpc_ruby_plugin
grpc_csharp_plugin grpc_php_plugin

进入它的bin目录就会发现带了很多编译插件,但是唯独没有golang的编译插件,这就是上面我说的golang插件改版,想cpp,python等安装grpc自带插件等语言编译方式与之前的编译方式相同,唯独golang的改了。

基础使用

protobuf相关

想要使用rpc调用,我们必须声明相关的service以及message,例如我们有如下这样一个proto文件

1
2
3
4
5
6
7
8
9
10
11
12
13
syntax = "proto3";
//option go_package = "/proto"; // 这地儿有点怪,生成grpc文件时可以使用:.在生成proto文件时只能使用/
option go_package = ",;"//生成grpc文件时使用
option go_package = "/proto"//生成proto文件时使用
message info{
string time = 1;
string info = 2;
string name = 3;
}

service say{
rpc SayHello(info) returns (info);
}

以上我们声明了一个名为info的message和一个名为say的service。

其中say服务中声明语法是

1
rpc func(param) returns (REST_T) // 关键字 函数名(函数参数) returns (返回类型)

函数参数和返回类型必须在proto文件中声明,不然proto文件使用时会因为找不到类型而报错。

server相关

我们先来看看如何起一个rpc服务,要想起一个rpc服务,首先我们要起一个tcp服务器,之后在注册相关的rpc服务器,然后监听即可。

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
package main

import (
pb "SayHello/proto"
"context"
"fmt"
"google.golang.org/grpc"
"log"
"net"
"time"
)

const port = ":9999" // 设置服务监听的端口
type routeGuideServer struct {
pb.UnimplementedSayServer //相关服务绑定
}

func (s routeGuideServer) SayHello(ctx context.Context, info *pb.Info) (*pb.Info, error) { //调用函数
cout := info.Name + info.Info + info.Time
fmt.Println(cout)
res := pb.Info{
Name: "server",
Info: "hello client",
Time: string(time.Time{}.Day()),
}
return &res,nil
}

func main() {
fmt.Println("hello world")
listen, err := net.Listen("tcp",port) //监听tcp
if err != nil {
log.Fatalln(err.Error())
}
grpcServer := grpc.NewServer()
pb.RegisterSayServer(grpcServer,&routeGuideServer{}) //注册服务
grpcServer.Serve(listen) // 监听服务
}

此时server的源码树目录如下

1
2
3
4
5
6
7
8
.
├── go.mod
├── go.sum
├── main.go
└── proto
├── message.pb.go
├── message.proto
└── message_grpc.pb.go

Client相关

我们需要注册一个相关的grpc服务,之后链接到相关的服务器。

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
package main

import (
pb "SayHelloClient/proto"
"context"
"fmt"
"google.golang.org/grpc"
"log"
"time"
)

const serverAddr = ":9999"
func Client() {
conn,err := grpc.Dial(serverAddr,grpc.WithInsecure()) // 注册服务
if err != nil {
fmt.Println(err.Error())
}
defer conn.Close() //延迟关闭
client := pb.NewSayClient(conn) //生成一个客户端
info := pb.Info{
Name: "client",
Info: "hello Server",
Time: string(time.Time{}.Day()),
}
resp, err := client.SayHello(context.Background(),&info)
if err != nil {
log.Fatalln(err.Error())
}
log.Printf("resp:%s",resp.GetName() + resp.Time + resp.Info)
}
func main() {
fmt.Println("Hello world")
Client()
}

源码树目录

1
2
3
4
5
6
7
8
.
├── go.mod
├── go.sum
├── main.go
└── proto
├── message.pb.go
├── message.proto
└── message_grpc.pb.go

编译

1
2
proto --go-grpc_out=:. *.proto
proto --go_out=:. *.proto

总结

用倒是不难用,就是grpc插件安装的时候坑比较多,之后还是流式服务,全双工服务,都大差不差这就不一一介绍了。