一个简单的用go语言开发gRPC程序例子。
安装gRPC
gRPC的安装需要3块内容
1. 安装gRPC环境
这个环境包括gRPC编译运行时刻需要的库。
$ go get google.golang.org/grpc
2. 安装 Protocol Buffers v3
这个是protoc编译器, 用来编译.proto文件生成gRPC服务的go代码。
直接从下面链接下载二进制发布包即可:
https://github.com/google/protobuf/releases
选择平台对应的zip包
protoc-<version>-<platform>.zip
解开之后在bin目录下面会有一个protoc可执行文件
3. 安装protoc plugin for Go
这个工具在go编译protoc文件的时候需要用到。
$ go get -u github.com/golang/protobuf/protoc-gen-go
安装完之后可执行程序protoc-gen-go会存放在$GOROOT/bin或者$GOPATH/bin下面。
一个ToUpper的例子
这个例子是一个ToUpper程序,接收客户端请求包含一个传入字符串参数,服务端返回大写字符串。
1. 定义protoc文件
$ cat proto/toupper.proto
syntax = "proto3";
package proto;
// The service definition.
service ToUpper{
// Sends a greeting
rpc Upper (UpperRequest) returns (UpperReply) {}
}
// The request message
message UpperRequest {
string name = 1;
}
// The response message
message UpperReply {
string message = 1;
}
定义了一个ToUpper服务,定义了两个消息UpperRequest和UpperReply分别用来接收和回复消息。
2. 定义服务端代码
$ cat main/server.go
package main
import (
"log"
"net"
"strings"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "toupper/proto"
"google.golang.org/grpc/reflection"
)
const (
port = ":50051"
)
type server struct{}
func (s *server) Upper(ctx context.Context, in *pb.UpperRequest) (*pb.UpperReply, error) {
log.Printf("Received: %s", in.Name)
return &pb.UpperReply{Message: strings.ToUpper(in.Name)}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterToUpperServer(s, &server{})
// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
3. 客户端代码
$ cat main/client.go
package main
import (
"log"
"os"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "toupper/proto"
)
const (
address = "localhost:50051"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewToUpperClient(conn)
// Contact the server and print out its response.
name := "hello world"
if len(os.Args) > 1 {
name = os.Args[1]
}
r, err := c.Upper(context.Background(), &pb.UpperRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Response: %s", r.Message)
}
工程目录结构如下
toupper
├── main
│ ├── client.go
│ └── server.go
├── makefile
└── proto
└── toupper.proto
makefile文件
$ cat makefile
PB=proto/toupper.pb.go
all: client server
server: $(PB)
go build main/server.go
client: $(PB)
go build main/client.go
$(PB):
protoc -I proto toupper.proto --go_out=plugins=grpc:proto
clean:
rm -f $(PB) client server
编译
$ make
protoc -I proto toupper.proto --go_out=plugins=grpc:proto
go build main/client.go
go build main/server.go
注意在编译前需要把前面安装的protoc和protoc-gen-go设置到PATH环境变量。
编译完总共会生成3个文件:
- proto/toupper.pb.go
- 可执行文件client, 和
- 可执行文件server
运行
在终端直接运行server:
$ ./server
在另一个终端运行client:
$ ./client
2017/10/27 15:54:10 Response: HELLO WORLD
$ ./client abcd
2017/10/27 15:54:14 Response: ABCD
这时我们可以看到在服务端的输出:
2017/10/27 15:54:10 Received: hello world
2017/10/27 15:54:14 Received: abcd