GO GRPC 学习笔记01

小钟钟同学 · · 579 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

简介:

gRPC是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。

环境:

WIN环境下:
GO 版本1.15
其他包的信息为:
    github.com/golang/protobuf v1.4.2
    golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
    golang.org/x/sys v0.0.0-20200915050820-6d893a6b696e // indirect
    golang.org/x/text v0.3.3 // indirect
    google.golang.org/genproto v0.0.0-20200914193844-75d14daec038 // indirect
    google.golang.org/grpc v1.32.0
    google.golang.org/protobuf v1.25.0

实践步骤:

1:下载protocbuf编译器

下载地址:https://github.com/google/protobuf/releases
然后选择对应的版本进行下载。

image.png

2:解压protocbuf并配置到环境变量

image.png

然后配置:D:\code\go\protoc-3.13.0\bin
到 电脑环境变量中。

3:打开cmd,运行protoc --version

成功打印当前版本信息证明安装成功了

4:安装GO下的相关包

新建项目


image.png

修改自己模块名称


image.png

4.1安装 golang 的proto工具包

go get -u github.com/golang/protobuf/proto
image.png

4.2安装 goalng 的proto编译支持

go get -u github.com/golang/protobuf/protoc-gen-go
image.png

4.3 安装 gRPC 包

go get -u google.golang.org/grpc
image.png

查看安装的依赖包:


image.png

5:编写proto文件(中间件文件)并编译

5.1 1.新建proto文件夹,在里面新建Prod.proto文件

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

package servies; //生成的文件包的存放包名称

// 定义发送请求信息
message ProdRequest{
  // 定义发送的参数
  // 参数类型 参数名 标识号(不可重复) 1  表示确定顺序
  int32 prod_id = 1;
}

// 定义响应信息返回信息
message ProdResponse{
  // 定义接收的参数
  // 参数类型 参数名 标识号(不可重复)
  int32 prod_stock = 1;
}


// 定义我们的服务(可定义多个服务,每个服务可定义多个接口)
service ProdService{
  rpc Route (ProdRequest) returns (ProdResponse){};
}

安装显示proto格式文件的插件


image.png

对应的项目目录:

image.png

5.1 2. 编译Prod.proto文件

D:\code\go\learngrpc>cd pdfiles

D:\code\go\learngrpc\pdfiles>protoc --go_out=plugins=grpc:../servies ./Prod.proto

提示不是


image.png

奇葩了,明明已经配置了还是不行!!!但是CMD可以,这样的话,那只能试一试把protoc.exe复制到GO安装目录bin下:

image.png

再进行执行命令OK:

D:\code\go\learngrpc\pdfiles>protoc --go_out=plugins=grpc:../servies ./Prod.proto

image.png

最终在package servies有对于的GO文件生成,此文件里面有对于的接口是生产,我们后续的服务就基于此接口的来实现对于的服务:

内容是:

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//  protoc-gen-go v1.25.0
//  protoc        v3.13.0
// source: Prod.proto

package servies

import (
    context "context"
    proto "github.com/golang/protobuf/proto"
    grpc "google.golang.org/grpc"
    codes "google.golang.org/grpc/codes"
    status "google.golang.org/grpc/status"
    protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    protoimpl "google.golang.org/protobuf/runtime/protoimpl"
    reflect "reflect"
    sync "sync"
)

const (
    // Verify that this generated code is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
    // Verify that runtime/protoimpl is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4

// 定义发送请求信息
type ProdRequest struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    // 定义发送的参数
    // 参数类型 参数名 标识号(不可重复) 1  表示确定顺序
    ProdId int32 `protobuf:"varint,1,opt,name=prod_id,json=prodId,proto3" json:"prod_id,omitempty"`
}

func (x *ProdRequest) Reset() {
    *x = ProdRequest{}
    if protoimpl.UnsafeEnabled {
        mi := &file_Prod_proto_msgTypes[0]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *ProdRequest) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*ProdRequest) ProtoMessage() {}

func (x *ProdRequest) ProtoReflect() protoreflect.Message {
    mi := &file_Prod_proto_msgTypes[0]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use ProdRequest.ProtoReflect.Descriptor instead.
func (*ProdRequest) Descriptor() ([]byte, []int) {
    return file_Prod_proto_rawDescGZIP(), []int{0}
}

func (x *ProdRequest) GetProdId() int32 {
    if x != nil {
        return x.ProdId
    }
    return 0
}

// 定义响应信息返回信息
type ProdResponse struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    // 定义接收的参数
    // 参数类型 参数名 标识号(不可重复)
    ProdStock int32 `protobuf:"varint,1,opt,name=prod_stock,json=prodStock,proto3" json:"prod_stock,omitempty"`
}

func (x *ProdResponse) Reset() {
    *x = ProdResponse{}
    if protoimpl.UnsafeEnabled {
        mi := &file_Prod_proto_msgTypes[1]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *ProdResponse) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*ProdResponse) ProtoMessage() {}

func (x *ProdResponse) ProtoReflect() protoreflect.Message {
    mi := &file_Prod_proto_msgTypes[1]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use ProdResponse.ProtoReflect.Descriptor instead.
func (*ProdResponse) Descriptor() ([]byte, []int) {
    return file_Prod_proto_rawDescGZIP(), []int{1}
}

func (x *ProdResponse) GetProdStock() int32 {
    if x != nil {
        return x.ProdStock
    }
    return 0
}

var File_Prod_proto protoreflect.FileDescriptor

var file_Prod_proto_rawDesc = []byte{
    0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, 0x65,
    0x72, 0x76, 0x69, 0x65, 0x73, 0x22, 0x26, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x71,
    0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x18,
    0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x64, 0x49, 0x64, 0x22, 0x2d, 0x0a,
    0x0c, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a,
    0x0a, 0x70, 0x72, 0x6f, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
    0x05, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x32, 0x45, 0x0a, 0x0b,
    0x50, 0x72, 0x6f, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x52,
    0x6f, 0x75, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x65, 0x73, 0x2e, 0x50,
    0x72, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x65, 0x72,
    0x76, 0x69, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
    0x65, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
    file_Prod_proto_rawDescOnce sync.Once
    file_Prod_proto_rawDescData = file_Prod_proto_rawDesc
)

func file_Prod_proto_rawDescGZIP() []byte {
    file_Prod_proto_rawDescOnce.Do(func() {
        file_Prod_proto_rawDescData = protoimpl.X.CompressGZIP(file_Prod_proto_rawDescData)
    })
    return file_Prod_proto_rawDescData
}

var file_Prod_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_Prod_proto_goTypes = []interface{}{
    (*ProdRequest)(nil),  // 0: servies.ProdRequest
    (*ProdResponse)(nil), // 1: servies.ProdResponse
}
var file_Prod_proto_depIdxs = []int32{
    0, // 0: servies.ProdService.Route:input_type -> servies.ProdRequest
    1, // 1: servies.ProdService.Route:output_type -> servies.ProdResponse
    1, // [1:2] is the sub-list for method output_type
    0, // [0:1] is the sub-list for method input_type
    0, // [0:0] is the sub-list for extension type_name
    0, // [0:0] is the sub-list for extension extendee
    0, // [0:0] is the sub-list for field type_name
}

func init() { file_Prod_proto_init() }
func file_Prod_proto_init() {
    if File_Prod_proto != nil {
        return
    }
    if !protoimpl.UnsafeEnabled {
        file_Prod_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*ProdRequest); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
        file_Prod_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*ProdResponse); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
    }
    type x struct{}
    out := protoimpl.TypeBuilder{
        File: protoimpl.DescBuilder{
            GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
            RawDescriptor: file_Prod_proto_rawDesc,
            NumEnums:      0,
            NumMessages:   2,
            NumExtensions: 0,
            NumServices:   1,
        },
        GoTypes:           file_Prod_proto_goTypes,
        DependencyIndexes: file_Prod_proto_depIdxs,
        MessageInfos:      file_Prod_proto_msgTypes,
    }.Build()
    File_Prod_proto = out.File
    file_Prod_proto_rawDesc = nil
    file_Prod_proto_goTypes = nil
    file_Prod_proto_depIdxs = nil
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// ProdServiceClient is the client API for ProdService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ProdServiceClient interface {
    Route(ctx context.Context, in *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error)
}

type prodServiceClient struct {
    cc grpc.ClientConnInterface
}

func NewProdServiceClient(cc grpc.ClientConnInterface) ProdServiceClient {
    return &prodServiceClient{cc}
}

func (c *prodServiceClient) Route(ctx context.Context, in *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error) {
    out := new(ProdResponse)
    err := c.cc.Invoke(ctx, "/servies.ProdService/Route", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

// ProdServiceServer is the server API for ProdService service.
type ProdServiceServer interface {
    Route(context.Context, *ProdRequest) (*ProdResponse, error)
}

// UnimplementedProdServiceServer can be embedded to have forward compatible implementations.
type UnimplementedProdServiceServer struct {
}

func (*UnimplementedProdServiceServer) Route(context.Context, *ProdRequest) (*ProdResponse, error) {
    return nil, status.Errorf(codes.Unimplemented, "method Route not implemented")
}

func RegisterProdServiceServer(s *grpc.Server, srv ProdServiceServer) {
    s.RegisterService(&_ProdService_serviceDesc, srv)
}

func _ProdService_Route_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(ProdRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(ProdServiceServer).Route(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/servies.ProdService/Route",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(ProdServiceServer).Route(ctx, req.(*ProdRequest))
    }
    return interceptor(ctx, in, info, handler)
}

var _ProdService_serviceDesc = grpc.ServiceDesc{
    ServiceName: "servies.ProdService",
    HandlerType: (*ProdServiceServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "Route",
            Handler:    _ProdService_Route_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "Prod.proto",
}

6:生成对应的服务实现相关生成的接口的文件信息

实现ProdServiceClient接口的方法:

type ProdServiceClient interface {
    Route(ctx context.Context, in *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error)
}

实现内容:

返回的是一个指针类型的

package servies

import (
    "context"
)
// 定义我们的服务
type ProdServies struct{}

//func (this *ProdServies)GetProdStock(ctx context.Context, request *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error)  {
//  return &ProdResponse{ProdStock: 20},nil
//}
// Route 实现Route方法
func (s *ProdServies) Route(ctx context.Context, req *ProdRequest) (*ProdResponse, error) {
    res := ProdResponse{ProdStock:req.ProdId}
    return &res, nil
}



image.png

7:创建服务端-新建一个server.go

注册的服务是基于上次生产的GO文件里面的

func RegisterProdServiceServer(s *grpc.Server, srv ProdServiceServer) {
    s.RegisterService(&_ProdService_serviceDesc, srv)
}

正式的内容信息为:

package main

import (
    "google.golang.org/grpc"
    "log"
    "net"
    "xiaozhong/servies"

)


func main() {
    // 监听本地端口// Address 监听地址// Network 网络通信协议
    listener, err := net.Listen("tcp", ":8000")
    if err != nil {
        log.Fatalf("net.Listen err: %v", err)
    }
    log.Println(" net.Listing...8000")
    // 新建gRPC服务器实例
    grpcServer := grpc.NewServer()
    // 在gRPC服务器注册我们的服务
    servies.RegisterProdServiceServer(grpcServer, &servies.ProdServies{})

    //用服务器 Serve() 方法以及我们的端口信息区实现阻塞等待,直到进程被杀死或者 Stop() 被调用
    err = grpcServer.Serve(listener)
    if err != nil {
        log.Fatalf("grpcServer.Serve err: %v", err)
    }
}

启动服务端:
看到启动信息为:


image.png

8:创建客户端client.go,访问服务端调用接口 获取信息-

package main

import (
    "context"
    "google.golang.org/grpc"
    "log"
    "xiaozhong/servies"
)

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

func main() {
    // 连接服务器
    conn, err := grpc.Dial(Address, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("net.Connect err: %v", err)
    }
    defer conn.Close()

    // 建立gRPC连接
    grpcClient := servies.NewProdServiceClient(conn)
    // 创建发送结构体
    req := servies.ProdRequest{
        ProdId: 15555,
    }
    // 调用我们的服务(Route方法)
    // 同时传入了一个 context.Context ,在有需要时可以让我们改变RPC的行为,比如超时/取消一个正在运行的RPC
    res, err := grpcClient.Route(context.Background(), &req)
    if err != nil {
        log.Fatalf("Call Route err: %v", err)
    }
    // 打印返回值
    log.Println(res)
}

运行的我们客户端:

image.png

PS:成功调用服务端的Server端的Route方法并获取返回我们自己传输的数据参数值。

最终的项目目录结构是:

image.png

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:小钟钟同学

查看原文:GO GRPC 学习笔记01

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

579 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传