gRPC 是由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制,据说是业界序列化速度最快的协议。
而grpc-go是grpc的一种,因为这是远程通信的,所以需要转化成字节序列,再以二进制序列的形式在网络上传送。所以我们在最开始的时候需要编写一个.proto 文件, 让protoc 编译器生成.pb.go方便后面的使用。
hello.proto文件
syntax = "proto3"; //指定语法版本
package helloword; //指定生成后的 hello.pb.go 的包名
//一个 RPC 服务通过参数和返回类型来指定可以远程调用的方法
service Hello {
// rpc 定义可远程调用服务
rpc HelloWorld (HelloRequest) returns (HelloReply) {}
}
//消息定义的关键字,相当于struct
message HelloRequest {
// [修饰符] 类型 字段名 = 标识符;
//标识符是用来在二进制格式中识别各个字段的,可以简单理解为序列化后的二进制数据中的布局位置顺序
string name = 1;
}
message HelloReply {
string message = 1;
}
在终端键入protoc -I . --go_out=plugins=grpc:. ./hello.proto
关于这行命令:
①-I
:指定对导入文件的搜索路径
②--go_out=
:指定生成文件的路径,这里指定了生成在当前路径
③plugins=grpc
: 用grpc plugin来执行这段protoc command
④./hello.proto
: 指定待编译的 proto文件
可以看到在当前路径会自动生成一个.pb.go
格式的文件
由于生成的hello.pb.go
内容比较多,就不铺上来了,下面开始实现服务端和客户端
服务端的实现
package main
import (
"google.golang.org/grpc"
pb "helloworld"
"net"
"log"
"context"
)
//用于实现HelloServer
type server struct{}
//服务实现
func (s *server) HelloWorld(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.Name)
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
func main() {
//监听
list, err := net.Listen("tcp", ":9999")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
//
ser := grpc.NewServer()
//注册到grpc
pb.RegisterHelloServer(ser, &server{})
//读取请求并响应
err = ser.Serve(list)
if err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
可以看出来服务端主要有两个工作,一个是实现我们当时在hello.proto
定义的服务接口service Hello
,要实现这个接口就要实现它所包含的所有方法,另一个是搭建grpc的服务器,用来监听来自客户端的请求和响应客户端
客户端的实现
package main
import (
pb "helloworld"
"google.golang.org/grpc"
"log"
"os"
"time"
"context"
)
func main() {
//连接服务端句柄
//WithInsecure()不指定安全选项
conn, err := grpc.Dial("localhost:9999", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
cli := pb.NewHelloClient(conn)
name := "World"
//获取命令行参数
if len(os.Args) > 1 {
name = os.Args[1]
}
//设置上下文超时
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
//响应
resp, err := cli.HelloWorld(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not succ: %v", err)
}
log.Printf("Receive from server: %s", resp.Message)
}
客户端的实现套路基本都是那个样,这里的这个安全选项是一种授权认证(如, TLS,GCE认证,JWT认证)
运行
go run server/main.go
go run client/main.go
参考
https://github.com/grpc/grpc-go/tree/master/examples/helloworld
http://doc.oschina.net/grpc?t=56831