跳到主要内容

GRPC

信息

RPC是Remote Procedure Call的简称,中文叫远程过程调用。 gRPC是由 google开发的一个高性能、通用的开源RPC框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多数流行的编程语言。

安装

下载地址

安装protoc的Golang gRPC插件

执行如下命令,会在 GOPATH 的 bin 目录下生成两个可执行文件:protoc-gen-go.exe 和 protoc-gen-go-grpc.exe。这两个插件可以用来生成Golang版本的proto协议代码和gRPC代理代码。

go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc

编写proto文件

proto文件是符合Protocol Buffers语言规范的数据交换协议文件,就像以前WebService定义服务时使用的XML文件。现在一般都是用proto3了,这里创建一个名为 hello.proto 的文件,放到项目的proto目录下:

syntax = "proto3"
option go_package="/proto";

package Business;

service Hello {
rpc Say (SayRequest) returns (SayResponse);
}

message SayResponse {
string Message = 1;
}

message SayRequest {
string Name = 1;
}

生成gRPC代理代码

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/hello.proto

也可以将文件生成到别的目录中,比如修改 proto 文件中 go_package 的配置为:

option go_package="/business";

然后执行下面的命令,会生成到项目下的business目录中:

protoc --go_out=.  --go-grpc_out=. proto/hello.proto

编写gRPC服务端程序

package main

import (
"context"
"fmt"
"grpcdemo/proto"
"net"

"google.golang.org/grpc"
)

type server struct {
proto.UnimplementedHelloServer
}

func (s *server) Say(ctx context.Context, req *proto.SayRequest) (*proto.SayResponse, error) {
fmt.Println("request:", req.Name)
return &proto.SayResponse{Message: "Hello " + req.Name}, nil
}

func main() {
listen, err := net.Listen("tcp", ":8001")
if err != nil {
fmt.Printf("failed to listen: %v", err)
return
}
s := grpc.NewServer()
proto.RegisterHelloServer(s, &server{})
//reflection.Register(s)

defer func() {
s.Stop()
listen.Close()
}()

fmt.Println("Serving 8001...")
err = s.Serve(listen)
if err != nil {
fmt.Printf("failed to serve: %v", err)
return
}
}

编写gRPC客户端程序

package main

import (
"bufio"
"context"
"fmt"
"grpchello/proto"
"os"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

func main() {

var serviceHost = "127.0.0.1:8001"

conn, err := grpc.Dial(serviceHost, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
fmt.Println(err)
}
defer conn.Close()

client := proto.NewHelloClient(conn)
rsp, err := client.Say(context.TODO(), &proto.SayRequest{
Name: "BOSIMA",
})

if err != nil {
fmt.Println(err)
}

fmt.Println(rsp)

fmt.Println("按回车键退出程序...")
in := bufio.NewReader(os.Stdin)
_, _, _ = in.ReadLine()
}