• 你好!欢迎你的到来
  • 关于我们
  • 首页 博客 学习笔记 技术导航 工具
  • 博文分类
    • PHP(43)
    • MySQL(11)
    • Linux(28)
    • html(3)
    • JQuery(4)
    • JavaScript(9)
    • svn(2)
    • CSS(2)
    • seajs(1)
    • go(44)
    • redis(1)
    • nginx(8)
    • mongo(0)
    • java(0)
    • 算法(0)
    • 其他(26)
    • 生活(1)
    专栏
    • Jquery基础教程
      • 文章:(15)篇
      • 阅读:28436
    • shell命令
      • 文章:(42)篇
      • 阅读:94037
    • Git教程
      • 文章:(36)篇
      • 阅读:162119
    • leetCode刷题
      • 文章:(76)篇
      • 阅读:43231
    • 摘要视图
    • 目录视图
    grpc的入门使用
    2019-06-30 11:16 阅读(12891) 评论(2)

    一、简介

    1、什么是grpc

    grpc是一个有google推出的、高性能、开源、通用的rpc框架。它是基于HTTP2协议标准设计开发,默认采用Protocol Buffers数据序列化协议,支持多种开发语言。

    2、什么是protobuf buffers

    ProtoBuf buffer 是一种数据表达方式,以.proto结尾的数据文件,可以类比json、xml等。

    针对ProtoBuf buffer 数据源,可以利用protoc 工具(下载安装地址:https://github.com/protocolbuffers/protobuf/releases),来生成各种语言的访问类。

    其操作主要:a、定义数据元;b、生成数据元的访问类

    优点:编解码速度更快、传输的数据更小。

    二、protobuf buffers定义数据元的语法

    一个.proto文件,主要包括以下部分:

    syntax = "proto3";
    package studentpb;
    service Student {
         rpc add (StudentReqs) returns (StudentReply) {} //新增学生接口
    }
    
    message StudentReqs {
        repeated StudentReq s = 1;
    }
    
    message StudentReq{
        string name= 1;
        int32 age = 2;
    }
    
    message StudentReply {
        int32 errno = 1;
        string errmsg = 2;
    }

    通过关键字syntax来指定使用的proto3语法。
    通过关键字package来定义一个包,需要注意避免命名冲突。

    通过关键字message来定义请求或相应需要使用的消息格式,里面可以包含了不同类型的字段 。一个.proto文件中,可以包含多个message的定义。

    通过关键字server来定一个服务。GRPC的服务是通过参数和返回类型来指定可以远程调用的方法。

    1、字段的约束规则

    a、repeated:前置repeated关键词,声明该字段为数组类型。

    b、proto3不支持proto2中的required和optional关键字。

    2、字段支持的类型

    支持基础类型、枚举类型、map类型、数组类型、message类型等。

    a、基础类型

    .protoC++JavaPythonGoRubyC#
    doubledoubledoublefloatfloat64Floatdouble
    floatfloatfloatfloatfloat32Floatfloat
    int32int32intintint32Fixnum or Bignumint
    int64int64longing/long[3]int64Bignumlong
    uint32uint32int[1]int/long[3]uint32Fixnum or Bignumuint
    uint64uint64long[1]int/long[3]uint64Bignumulong
    sint32int32intintjint32Fixnum or Bignumint
    sint64int64longint/long[3]int64Bignumlong
    fixed32uint32int[1]intuint32Fixnum or Bignumuint
    fixed64uint64long[1]int/long[3]uint64Bignumulong
    sfixed32int32intintint32Fixnum or Bignumint
    sfixed64int64longint/long[3]int64Bignumlong
    boolboolbooleanbooleanboolTrueClass/FalseClassbool
    stringstringStringstr/unicode[4]stringString(UTF-8)string
    bytesstringByteStringstr[]byteString(ASCII-8BIT)ByteString

    b、枚举类型

    syntax = "proto3";
    
    message Student{
      string name = 1;
      // 定义enum类型
      enum Sex {
        BOY = 0;
        GIRL = 1;
      }
      Sex sex = 1; // 使用Corpus作为字段类型
    }

    c、message类型

    syntax = "proto3";
    
    message Students {
        repeated Student s = 1;
    }
    
    message Student{
      string name = 1;
      // 定义enum类型
      enum Sex {
        BOY = 0;
        GIRL = 1;
      }
      Sex sex = 4; // 使用Corpus作为字段类型
    }

    二、如何利用protoc 工具生成访问类

    1、prooc常用参数

    参数名简介
    -I指定import路径,可以指定多个-I参数,编译时按顺序查找,不指定时默认查找当前目录
    --go_out指定输出go语言的访问类,其他语言可以参考:https://github.com/grpc/grpc
    plugins指定依赖的插件

    2、案例1

    文件目录如下:

    ├── protobuf

    │   └── t.proto

    └── main.go

    其中“t.proto”内容如下:

    syntax = "proto3";
    package studentpb;
    service Student {
         rpc add (StudentReqs) returns (StudentReply) {} //新增学生接口
    }
    
    message StudentReqs {
        repeated StudentReq s = 1;
    }
    
    message StudentReq{
        string name= 1;
        int32 age = 2;
    }
    
    message StudentReply {
        int32 errno = 1;
        string errmsg = 2;
    }

    生成go访问类的语句如下:

     protoc --go_out=plugins=grpc:. protobuf/*.proto

    三、GO如何利用GRPC通信

    1、pb文件

    syntax = "proto3";
    package studentpb;
    service Student {
         rpc add (StudentReqs) returns (StudentReply) {} //新增学生接口
    }
    
    message StudentReqs {
        repeated StudentReq s = 1;
    }
    
    message StudentReq{
        string name= 1;
        int32 age = 2;
    }
    
    message StudentReply {
        int32 errno = 1;
        string errmsg = 2;
    }

    执行如下命令,生成grpc访问类

    protoc --go_out=plugins=grpc:. *.proto

    2、服务端

    目录结构如下:

    main.go内容如下:

    package main
    
    import (
       "context"
       "fmt"
       "google.golang.org/grpc"
       "log"
       "net"
       "test/studentpb"
    )
    
    type Student struct {
    }
    
    // 新增students
    func (r *Student) Add(ctx context.Context, in *studentpb.StudentReqs) (*studentpb.StudentReply, error) {
       return &studentpb.StudentReply{
          Errno:  0,
          Errmsg: "ok",
       }, nil
    }
    
    func main() {
       // 建立server监听
       rpcAddr := "127.0.0.1:8601"
       server, err := net.Listen("tcp", rpcAddr)
       if err != nil {
          fmt.Println("failed to listen", rpcAddr)
          panic(err)
       }
    
       // 建立rpc server
       var RpcServer = grpc.NewServer()
    
       // 对外提供服务
       r := new(Student)
       studentpb.RegisterStudentServer(RpcServer, r)
       
       // 开始接受请求
       err = RpcServer.Serve(server)
       if err != nil {
          log.Fatalf("failed to listen: %v", err)
       }
    }

    3、用户端

    用户端的目录结构和服务端一样。main.go的内容如下:

    package main
    
    import (
       "context"
       "fmt"
       "google.golang.org/grpc"
       "test/studentpb"
       "time"
    )
    
    func main() {
       addr := "127.0.0.1:8601"
       timeout := 10
    
       //建立rpc通道
       client, err := grpc.Dial(addr, grpc.WithInsecure())
       if err != nil {
          panic("连接失败")
       }
       defer client.Close()
    
       // 创建studentrpc对象
       rpcClient := studentpb.NewStudentClient(client)
    
       // 创建上线文
       ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
       defer cancel()
    
       //封装请求参数
       req := &studentpb.StudentReqs{}
       req.S = append(req.S, &studentpb.StudentReq{Name:"张三", Age:12})
    
       // 打印结果
       res , err := rpcClient.Add(ctx, req)
       if err != nil {
          fmt.Println("请求错误", err)
       } else {
          fmt.Println(res.GetErrno(), res.GetErrmsg())
       }
    }


    本文为原创文章,请尊重辛勤劳动,如需转载,请保留本文地址
    http://www.findme.wang/blog/detail/id/680.html

    若您感觉本站文章不错,读后有收获,不妨赞助一下?

    我要赞助

    您还可以分享给朋友哦

    更多
    顶
    9
    踩
    0
    • 上一篇: influxdb的使用(一)
    • 下一篇: goland中粘贴后如何保持原来的缩进​
    • 查看评论
    • 正在加载中...
    • 留言
    • 亲,您还没有登录,登录后留言不需要审核哦!
      可以使用如下方式登录哦!
  • CSDN | 新浪微博 | github | 关于我们 | 我要留言 | 友链申请
  • 豫ICP备18038193号    Copyright ©lidequan All Rights Reserved