golang grpc使用

protoc buf和grpc的关系

protoc buf是一种数据压缩格式,因为是二进制格式的,比xml、json序列化快很多。
gRPC由google开发,是一款语言中立、平台中立、开源的远程过程调用系统,基于HTTP2协议标准设计开发
gRPC可以实现微服务,将大的项目拆分为多个小且独立的业务模块,也就是服务,各服务间使用高效的protobuf协议进行RPC调用,gRPC默认使用protocol buffers
支持多种开发语言
golang grpc使用_第1张图片
一次RPC的完整流程:

客户端(gRPC Sub)调用 A 方法,发起 RPC 调用
对请求信息使用 Protobuf 进行对象序列化压缩(IDL)
服务端(gRPC Server)接收到请求后,解码请求体,进行业务逻辑处理并返回
对响应结果使用 Protobuf 进行对象序列化压缩(IDL)
客户端接受到服务端响应,解码请求体。回调被调用的 A 方法,唤醒正在等待响应(阻塞)的客户端调用并返回响应结果
我们在protobuf协议定义上扩展一个类型定义:Service,这在RPC通讯上有着重要作用。

gRPC实战例子

hello.proto编写

syntax = "proto3"; // 指定proto版本

// 指定golang包名
option go_package = "pb/proto_demo";

// 定义Hello服务
service Hello {
// 定义SayHello方法
rpc SayHello(HelloRequest) returns (HelloResponse) {}
rpc SayHi(HiRequest) returns (HiResponse) {}
}

// HelloRequest 请求结构
message HelloRequest {
string name = 1;
}

// HelloResponse 响应结构
message HelloResponse {
string message = 1;
}

// HiRequest 请求结构
message HiRequest {
string name = 1;
string school = 2;
int32 age = 3;
int32 grade = 4;
int32 status = 5;
}

// HiResponse 响应结构
message HiResponse {
string message = 1;
int32 status = 2;
}

用protoc编译生成grpc版本的protobuf go文件

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

注意,–go_out告诉protoc编译proto文件生成的目标代码为go代码,–go-grpc_out告诉生成grpc版本的。
这时候会得到2个文件,hello.pb.go和hello_grpc.pb.go,

编写服务端代码

package main

import (
	"fmt"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
	"net"
	"test/protouse/pb/proto_demo"
)

const (
	// gRPC服务地址
	Address = "127.0.0.1:9988"
)

type helloService struct {
	proto_demo.HelloServer
}

var HelloService = helloService{}

func (h helloService) SayHello(ctx context.Context, in *proto_demo.HelloRequest) (*proto_demo.HelloResponse, error) {
	resp := new(proto_demo.HelloResponse)
	resp.Message = fmt.Sprintf("yswHello %s.", in.Name)

	return resp, nil
}

func (h helloService) SayHi(ctx context.Context, in *proto_demo.HiRequest) (*proto_demo.HiResponse, error) {
	resp := new(proto_demo.HiResponse)
	resp.Message = fmt.Sprintf("yswHi %s, grade=%d, school=%s, grade=%d, status=%d", in.Name, in.Grade, in.School, in.Grade, in.Status)

	return resp, nil
}

func main() {
	//test := &proto_demo.Student{
	//	Name: "yangshengwen",
	//	Male: true,
	//	Scores: []int32{23,98, 88},
	//	Subject: map[string]int32{"age":28, "level":2},
	//}
	//
	//data,err := proto.Marshal(test)
	//if err != nil {
	//	fmt.Println("proto encode err:", err)
	//	return
	//}
	//fmt.Printf("data size:%d\n", len(data))
	//
	//newTest := &proto_demo.Student{}
	//err = proto.Unmarshal(data, newTest)
	//if err != nil {
	//	fmt.Println("proto encode err:", err)
	//	return
	//}
	//
	//fmt.Printf("name:%v, Male:%v, Scores:%v, Subject:%v", newTest.Name, newTest.Male, newTest.Scores, newTest.Subject)


	listen, err := net.Listen("tcp", Address)
	if err != nil {
		grpclog.Fatalf("Failed to listen: %v", err)
	}

	s := grpc.NewServer()

	proto_demo.RegisterHelloServer(s, HelloService)
	fmt.Println("Listen on " + Address)
	grpclog.Println("Listen on " + Address)
	s.Serve(listen)

}

启动server, go run server.go或者编译再运行,就会在对应的端口监听。
golang grpc使用_第2张图片

编写client端代码

package main

import (
	"fmt"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
	"test/protouse/pb/proto_demo"
)
const (
	// gRPC服务地址
	Address = "127.0.0.1:9988"
)


func main() {
	conn, err := grpc.Dial(Address, grpc.WithInsecure())
	if err != nil {
		grpclog.Fatalln(err)
	}
	defer conn.Close()

	c := proto_demo.NewHelloClient(conn)

	req := &proto_demo.HelloRequest{Name:"grpc"}
	res, err := c.SayHello(context.Background(), req)
	if err != nil {
		grpclog.Fatalln(err)
	}

	fmt.Println(res.Message)

	req2 := &proto_demo.HiRequest{Name:"grpc", Grade:3, Age:10, Status:2, School:"zhuhai"}
	res2, err := c.SayHi(context.Background(), req2)
	if err != nil {
		grpclog.Fatalln(err)
	}

	fmt.Println(res2.Message)
}

hello_grpc.pb.go里有对应的client实例以及接口,参数用hello.pb.go里对应的结构体。
启动client,go run client.go, 正确得到server进程的回复。
在这里插入图片描述

你可能感兴趣的:(go开发实战,golang,rpc,java)