gRPC学习笔记

gRPC学习笔记

一、gRPC介绍

gRPC是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ErO385KK-1640622187958)(C:\Users\v_rwsnowguo\Desktop\图库\pic\2021\12\Snipaste_2021-12-03_16-09-45.png)]

1.1 gRPC vs. Restful API

gRPC和restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议(严格地说, gRPC使用的http2.0,而restful api则不一定)。不过gRPC还是有些特有的优势,如下:

  • gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件
  • 通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。
  • gRPC可以方便地支持流式通信(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的restful api似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用。)

1.2 四类服务方法

  • 单项RPC,即客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。

    rpc SayHello(HelloRequest) returns (HelloResponse);
    
  • 服务端流式 RPC,即客户端发送一个请求给服务端,可获取一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。

    rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
    
  • 客户端流式 RPC,即客户端用提供的一个数据流写入并发送一系列消息给服务端。一旦客户端完成消息写入,就等待服务端读取这些消息并返回应答。

    rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
    
  • 双向流式 RPC,即两边都可以分别通过一个读写数据流来发送一系列消息。这两个数据流操作是相互独立的,所以客户端和服务端能按其希望的任意顺序读写

    rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
    

二、Protobuf

Protobuf是由google开发的一套开源序列化协议框架,类似于XML,JSON,采用协议序列化用于数据存储与读取,与XML相比,定义了数据格式更加简单,数据访问接口可以自动化生成,加快了开发者开发速度

2.1 安装

win安装

pip install grpcio-tools

到https://github.com/protocolbuffers/protobuf/releases下载对应的安装包,并将protoc.exe放在PATH

ubuntu安装

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

到https://github.com/protocolbuffers/protobuf/releases下载对应的安装包,并将protoc放在PATH

2.2 使用protoc生成代码

# python
protoc --python_out=. api.proto

# go
protoc --go_out=plugins=grpc:. api.proto

2.2 protobuf语法

采用Message定义(class),字段格式如下

[rules][data_type] [data_name] = [number] [default = obj]

Rules:定义该变量的规则

  • required:必须的
  • optional:可选的。如果未设置可选字段值,则使用默认值default
  • repeated:可以重复任意次数(包括零次),类似数组。

DataType:数据类型

常用数据类型有int32, int64, float, double, bool, string, bytes

DataName:字段名称

Number:唯一的数值型标识符

Protobuf是采用key-value形式,将成员名映射为number,这样就能实现数据的序列化.每个数据字段都有唯一的数值型标识符.这些标识符用于标识字段在消息中的二进制格式,使用中的类型不应该随意改动。需要注意的是,[1-15]内的标识在编码时只占用一个字节,包含标识符和字段类型。[16-2047]之间的标识符占用2个字节。

例子

syntax = "proto2";
 
message Person {
  required int32 age = 1;
  required string name = 2;
}
 
message Family {
  repeated Person person = 1;
}

三、grpc项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2lagTcg3-1640622187959)(C:\Users\v_rwsnowguo\Desktop\图库\pic\2021\12\Snipaste_2021-12-16_10-26-38.png)]

3.1 go.mod

module go-study

go 1.17

require (
	google.golang.org/grpc v1.42.0
	google.golang.org/protobuf v1.27.1
)

require (
	github.com/golang/protobuf v1.5.2 // indirect
	golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
	golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect
	golang.org/x/text v0.3.0 // indirect
	google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
)

3.2 proto

shop.proto

syntax = "proto3";// 协议为proto3

package proto;

option go_package = "./";

// 定义发送请求信息
message ProdRequest {
  int32 prod_id = 1; // 商品ID
}

// 定义响应信息
message ProdResponse {
  optional int32 prod_id = 1;
  repeated string prod_name = 2 ; // 商品名称
}

// 定义服务
service ProdService {
  rpc GetProd(ProdRequest) returns(ProdResponse);
}

根据proto文件生成go文件

protoc --go_out=plugins=grpc:./proto ./proto/shop.proto

3.3 service

ProdService.go

package service

import (
	"context"
	"fmt"
)
import . "go-study/proto"

type ProdService struct {
}

func (this *ProdService) GetProd(ctx context.Context, req *ProdRequest) (*ProdResponse, error) {
	prodId := req.GetProdId()
	fmt.Println("get--", prodId)
	prodNames := []string{"奶茶", "可乐"}
	return &ProdResponse{ProdId: &prodId, ProdName: prodNames}, nil
}

3.4 server

server.go

package main

import (
	db "go-study/proto"
	svr "go-study/service"
	"google.golang.org/grpc"
	"log"
	"net"
)

const (
	// Address 监听地址
	ADDRESS string = ":8081"
	// Network 网络通信协议
	NETWORK string = "tcp"
)

func main() {
	// 监听本地端口
	lis, err := net.Listen(NETWORK, ADDRESS)
	if err != nil {
		log.Fatal("Net.Listen err: %v", err)
	}
	// 新建gRPC服务器实例
	server := grpc.NewServer()
	// 注册服务
	db.RegisterProdServiceServer(server, new(svr.ProdService))
	err = server.Serve(lis)
	if err != nil {
		return
	}
}

3.5 client

client.go

package main

import (
	ctx "context"
	"fmt"
	db "go-study/proto"
	"google.golang.org/grpc"
	"log"
)

const (
	// Address 连接地址
	Address string = "127.0.0.1:8081"
)

func main() {
	conn, err := grpc.Dial(Address, grpc.WithInsecure())
	//grpc.WithInsecure()禁止安全验证传输
	if err != nil {
		log.Fatalf("net.Connect err: %v", err)
	}
	defer conn.Close()
	// 建立gRPC连接
	client := db.NewProdServiceClient(conn)
	res, err := client.GetProd(ctx.Background(), &db.ProdRequest{ProdId: 12})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(res)
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值