参考:
B站:【rpc】grpc为例了解rpc的用法
go gRPC初体验(win10+普通网络)
GRPC快速入门
go-protoc导出时遇到protoc-gen-go: unable to determine Go import path解决方法
一、安装protoc
1、什么是protobuf
protobuf也叫protocol buffer是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。
由于它是一种二进制的格式,比使用 xml 、json进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。
2、安装protoc
grpc使用protocol buffers作为IDL(interface description languag),这很好理解,都是谷歌出的,而使用grpc,第一步其实就是自己写好proto文件,然后使用protoc命令生成go语言包,所以,我们首先要装protoc命令,这个东西我一开始一看还挺恐慌的,想着是不是得编译安装啥的,后来发现并不用,直接下载现成的exe文件就完事儿了,这里直接给出网址 https://github.com/protocolbuffers/protobuf/releases
这个网址打开是这样的:
选择自己的版本:
下下来之后,解压,然后,直接将bin里面的exe文件,就是下面这个,拷贝到PATH里的任一一个路径下面就行,既然我是为了用它做go语言的grpc,所以我选择了把它放在我的GOROOT/bin里面。
然后,打开cmd验证一下,输入
protoc --version
看到版本号,就说明protoc安装成功了。
二、安装grpc包
安装 gRPC:
go get -u -v google.golang.org/grpc
安装 protoc-gen-go:
go get -v -u github.com/golang/protobuf/protoc-gen-go
新建一个helloworld文件夹,在里面新建一个helloworld.proto文件,把grpc包里提供的helloworld.proto文件内容拷贝进去,proto文件内容是这些:
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package helloworld;
option go_package = "./";
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
proto大概意思如下:
syntax = “proto3” 这个就是指定proto版本,我们一开始是装的就是3.11,所以这里也是proto3
option 这几行我是真的毫无头绪,这不是go么,跟java有啥关系。。。
package helloworld 这行好理解,就是用protoc命令生成的go代码的包名,因为后面写客户端服务器程序都要引用这个包,所以就叫helloworld了,也就是跟所在路径同名
service 这块呢,就是定义了这个远程调用的服务,服务请求者调用SayHello方法,请求中携带HelloRequest格式的信息,服务提供者则返回HelloReply格式的回复
message 这个就是定义请求和回复的格式,这个例子里请求和格式都是简单的string
接下来就是生成对应的go语言代码,这里终于要用到我们最开始安装的protoc了,命令如下:
protoc --go_out=plugins=grpc:. helloworld.proto
错误:
解决:
在代码中添加:option go_package = "./";
问题解决了之后,没有报错,而且成功生成了一个go文件:
三、使用
1、编码
go代码也生成了,接下来我们就可以使用这些生成好的代码,写一个客户端,一个服务器,体验一下rpc了。
客户端和服务器的程序呢,我也是用的grpc的helloworld包里面提供的,为了模拟这是我自己写的一个rpc,我又把里面的内容拷出来放到我自己新建的文件里了。
首先,自己新建一个client.go,一个server.go。
然后,把grpc包helloword里的客户端和服务器程序相应的贴进去。
贴进去之后,改一下,import,改成我们刚刚自己生成的helloworld包。
最终的server.go如下:
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package main implements a server for Greeter service.
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
client.go代码如下:
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package main implements a client for Greeter service.
package main
import (
"context"
"log"
"os"
"time"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
address = "localhost:50051"
defaultName = "world"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
name := defaultName
if len(os.Args) > 1 {
name = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
2、运行
先服务器跑起:
客户端走起,注意这里客户端和服务器分别跑在两个terminal里:
也打印到了接收到的信息,完美!
到这里,go语言grpc初体验就算是成功收尾了。
四、总结
总结一下,当我们需要增加一个grpc接口的时候,其实就是以下几步:
- 修改proto文件,新增一个service,以及相应的请求和回复的message
- 使用protoc生成go代码
- 在服务器调用者和服务提供者的代码里分别调用生成的go包里的方法