七叶笔记 » golang编程 » Golang gRPC 学习案例

Golang gRPC 学习案例

gRPC是由 google 主导开发的RPC框架,使用HTTP/2协议并用ProtoBuf作为序列化工具。

例1.该示例源自gRPC-go的examples的helloworld

proto文件

syntax = “proto3”;

option objc_class_prefix = “HLW”;

package helloworld;

service Greeter {

rpc SayHello (HelloRequest) returns (HelloReply) {}

}

Message HelloRequest {

string name = 1;

}

message HelloReply {

string message = 1;

}

service定义了一个 server 。其中的接口可以是四种类型

a.rpc Get Feature (Point) returns (Feature) {} 类似普通的函数调用,客户端发送请求Point到服务器,服务器返回相应Feature.

b.rpc ListFeatures(Rectangle) returns (stream Feature) {}客户端发起一次请求,服务器端返回一个流式数据,比如一个数组中的逐个元素

c.rpc RecordRoute(stream Point) returns (RouteSummary) {}

客户端发起的请求是一个流式的数据,比如数组中的逐个元素,服务器返回一个相应

d.rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}

客户端发起的请求是一个流式数据,比如数组中的逐个元素,二服务器返回的也是一个类似的数据结构

2.使用protoc命令生成相关文件:

protoc –go_out=plugins=grpc:. helloworld.proto

helloworld.pb.go helloworld.proto

生成对应的pb.go文件。

3.服务端程序

package main

import (

“log”

net

pb “your_path_to_gen_pb_dir/helloworld”

“golang.org/x/net/context”

“google.golang.org/grpc”

)

const (

port = “:50051”

)

type server struct{}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {

return &pb.HelloReply{Message: “Hello ” + in.Name}, nil

}

func main() {

lis, err := net.Listen(“tcp”, port)

if err != nil {

log.Fatalf(“failed to listen: %v”, err)

}

s := grpc.NewServer() //调用grpc.NewServer() 创建一个server s

pb.RegisterGreeterServer(s, &server{}) //注册这个server s到结构server上面

s.Serve(lis)

}

4.客户端程序:

package main

import (

“log”

“os”

pb “your_path_to_gen_pb_dir/helloworld”

“golang.org/x/net/context”

“google.golang.org/grpc”

)

const (

address = “localhost:50051”

defaultName = “world”

)

func main() {

conn, err := grpc.Dial(address, grpc.WithInsecure())

if err != nil {

log.Fatalf(“did not connect: %v”, err)

}

defer conn.Close()

c := pb.NewGreeterClient(conn)

name := defaultName

if len(os. Args ) > 1 {

name = os.Args[1]

}

r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})

if err != nil {

log.Fatalf(“could not greet: %v”, err)

}

log.Printf(“Greeting: %s”, r.Message)

}

先运行服务器,在运行客户端,可以看到。

./greeter_server &

./greeter_client

2018/03/10 21:42:19 Greeting: Hello world

例2.ProtoBuf作为序列化

1、下载protobuf的编译器protoc

下载:protoc-3.3.0-linux-x86_64.zip解压,把bin目录下的protoc复制到GOPATH/bin下,GOPATH/bin加入环境变量。

获取protobuf的编译器插件protoc-gen-go,进入GOPATH目录

go get -u github.com/golang/protobuf/protoc-gen-go,如果成功,会在GOPATH/bin下生成protoc-gen-go.exe文件

2.创建一个test.proto文件

//指定版本

syntax = “proto3”;

package test;

//手机类型

//枚举类型第一个字段必须为0

enum PhoneType {

HOME = 0;

WORK = 1;

}

//手机

message Phone {

PhoneType type = 1;

string number = 2;

}

//人

message Person {

//后面的数字表示标识号

int32 id = 1;

string name = 2;

//repeated表示可重复

//可以有多个手机

repeated Phone phones = 3;

}

//联系簿

message ContactBook {

repeated Person persons = 1;

}

3.运行如下命令

protoc –go_out=. *.proto

会生成一个test.pb.go的文件

4.在go语言中使用protobuf

package main;

import (

“github.com/golang/protobuf/proto”

“protobuf/test”

“io/ioutil”

“os”

“fmt”

)

func write() {

p1 := &test.Person{

Id: 1,

Name: “小张”,

Phones: []*test.Phone{

{test.PhoneType_HOME, “111111111”},

{test.PhoneType_WORK, “222222222”},

},

};

p2 := &test.Person{

Id: 2,

Name: “小王”,

Phones: []*test.Phone{

{test.PhoneType_HOME, “333333333”},

{test.PhoneType_WORK, “444444444”},

},

};

//创建地址簿

book := &test.ContactBook{};

book.Persons = append (book.Persons, p1);

book.Persons = append(book.Persons, p2);

//编码数据

data, _ := proto.Marshal(book);

//把数据写入文件

ioutil.WriteFile(“./test.txt”, data, os.ModePerm);

}

func read() {

//读取文件数据

data, _ := ioutil.ReadFile(“./test.txt”);

book := &test.ContactBook{};

//解码数据

proto.Unmarshal(data, book);

for _, v := range book.Persons {

fmt.Println(v.Id, v.Name);

for _, vv := range v.Phones {

fmt.Println(vv.Type, vv.Number);

}

}

}

func main() {

write();

read();

}

结果:

1 小张

HOME 1111111111

WORK 2222222222

2 小王

HOME 3333333333

WORK 4444444444

相关文章