所有文章

gRPC使用指南

gRPC是一个由google开源的RPC框架,它支持多种语言之间的相互调用,依赖开源项目google/protobuf作为序列化工具。

本文通过一个demo来介绍gRPC使用方法,demo的服务端和客户端都用golang来编写。

准备环境

安装golang

golang的版本要大于等于1.6

go version

然后设置好GOROOT、GOPATH,并且把$GOPATH/bin加到系统的PATH中。

echo $GOROOT
echo $GOPATH

安装gRPC

gRPC是用golang编写的,可以直接用go命令行下载:

go get -u -v google.golang.org/grpc

安装Protocol Buffers

目前没有用golang写的版本,不能直接get下来,最好去github下载已经编译好的二进制,选择自己的平台,版本3.0以上,比如64位linux就选protoc-3.5.1-linux-x86_64.zip这个包,解压后把二进制文件放到自己的$GOPATH/bin下:

$ protoc --version
libprotoc 3.5.1

安装Protocol Buffers GO插件

go get -u -v github.com/golang/protobuf/protoc-gen-go
go install -v github.com/golang/protobuf/protoc-gen-go

编写一个demo

新建一个名为grpc的golang项目,结构如下:

grpc
├── client
│   └── main.go
├── proto
│   ├── grpc.pb.go
│   └── grpc.proto
└── server
    └── main.go

编写生成共享函数库的模版

grpc/proto/grpc.proto

syntax = "proto3";

package proto;

// 定义一个RPC Server
// 包含两个函数可供Client调用
service Greeter {
  rpc AddUser (UserRequest) returns (UserResponse);
  rpc GetUser (UserRequest) returns (UserResponse);
}
// 调用时的数据格式
message UserRequest {
	string Name = 1;
	int32 age = 2;
	string address = 3;
}
// 返回值的数据格式
message UserResponse {
	string Name = 1;
	int32 age = 2;
	string address = 3;
}

生成共享函数库

protoc proto/grpc.proto --go_out=plugins=grpc:. && ls proto
grpc.pb.go  grpc.proto

执行成功会在proto目录下生成一个grpc.pb.go源文件,这个源文件中定义了Server和Client类,并且它们具有相同的函数,这样的话就不会出现客户端调用了服务器上并不存在的方法。

编写RPC服务端

grpc/server/main.go

package main

import (
	"context"
	pb "kspark/grpc/proto"
	"log"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

// 实现kspark/grpc/proto包中的GreeterServer接口
type server struct{}

func (*server) AddUser(ctx context.Context, user *pb.UserRequest) (*pb.UserResponse, error) {
	log.Println("add user:", user.Name)
	return &pb.UserResponse{
		Name: user.Name + " a year older",
		Age:  user.Age + 1,
	}, nil
}

func (*server) GetUser(ctx context.Context, user *pb.UserRequest) (*pb.UserResponse, error) {
	log.Println("get user:", user.Name)
	return &pb.UserResponse{
		Name: user.Name + " be get",
	}, nil
}

func main() {
	// 监听一个端口
	lis, err := net.Listen("tcp", "localhost:8081")
	if err != nil {
		log.Fatal(err)
	}
	// 创建一个RPC服务端并启动
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})

	reflection.Register(s)
	if err := s.Serve(lis); err != nil {
		log.Fatal("failed to serve: %v", err)
	}
}

编写RPC客户端

grpc/client/main.go

package main

import (
	"context"
	pb "kspark/grpc/proto"
	"log"

	"google.golang.org/grpc"
)

var address = "localhost:8081"

func main() {
	// 连接到端口
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatal("can not connect to server:", address)
	}
	defer conn.Close()

	// 创建RPC客户端
	client := pb.NewGreeterClient(conn)

	// 调用服务器中的AddUser方法,并得到返回值
	result, err := client.AddUser(context.Background(), &pb.UserRequest{
		Name: "jack",
		Age:  18,
	})
	if err != nil {
		log.Println("failed AddUser")
	}

	log.Printf("success AddUser => Name:%v, Age:%v\n", result.Name, result.Age)
}

启动服务端

go run server/main.go

启动客户端

go run clinet/main.go

2017/12/31 17:46:02 success AddUser => Name:jack a year older, Age:19

编写日期:2017-12-31