🧭
区块链技术指南
  • 前言
  • 修订记录
  • 如何贡献
  • 区块链的诞生
    • 记账科技的千年演化
    • 分布式记账与区块链
    • 集大成者的比特币
    • 区块链的商业价值
    • 本章小结
  • 核心技术概览
    • 定义与原理
    • 技术的演化与分类
    • 关键问题和挑战
    • 趋势与展望
    • 认识上的误区
    • 本章小结
  • 典型应用场景
    • 应用场景概览
    • 金融服务
    • 征信管理
    • 权属管理与溯源
    • 资源共享
    • 物流与供应链
    • 物联网
    • 数字艺术品和 NFT
    • 其它场景
    • 本章小结
  • 分布式系统核心技术
    • 一致性问题
    • 共识算法
    • FLP 不可能原理
    • CAP 原理
    • ACID 原则与多阶段提交
    • Paxos 算法与 Raft 算法
    • 拜占庭问题与算法
    • 可靠性指标
    • 本章小结
  • 密码学与安全技术
    • 密码学简史
    • Hash 算法与数字摘要
    • 加解密算法
    • 消息认证码与数字签名
    • 数字证书
    • PKI 体系
    • Merkle 树结构
    • Bloom Filter 结构
    • 同态加密
    • 其它技术
    • 本章小结
  • 比特币 —— 初露锋芒的区块链
    • 比特币项目简介
    • 比特币诞生背景
    • 工作原理
    • 挖矿过程
    • 共识机制
    • 闪电网络
    • 侧链
    • 热门问题
    • 相关工具
    • 本章小结
  • 以太坊 —— 挣脱加密货币的枷锁
    • 以太坊项目简介
    • 核心概念
    • 主要设计
    • 相关工具
    • 安装客户端
    • 使用智能合约
    • 智能合约案例:投票
    • 本章小结
  • 超级账本 —— 面向企业的分布式账本
    • 超级账本项目简介
    • 社区组织结构
    • 顶级项目介绍
    • 开发必备工具
    • 贡献代码
    • 本章小结
  • Fabric 安装与部署
    • 简介
    • 本地编译组件
    • 容器方式获取
    • 本地方式启动 Fabric 网络
    • 容器方式启动 Fabric 网络
    • 本章小结
  • 管理 Fabric 网络
    • 简介
    • 使用通道
    • 管理节点
    • 管理链上代码
    • 监听网络事件
    • 自动发现网络信息
    • 使用运维服务
    • 如何升级网络版本
    • 使用 SDK
    • 注意事项与最佳实践
    • 本章小结
  • 智能合约开发
    • 简介
    • 链码概念与结构
    • 示例一:信息公证
    • 示例二:交易资产
    • 示例三:数字货币发行与管理
    • 示例四:学历认证
    • 示例五:社区能源共享
    • 小结
  • Fabric 架构与设计
    • 简介
    • 架构设计
    • 消息协议
    • 小结
  • 区块链服务平台设计
    • 简介
    • IBM Bluemix 云区块链服务
    • 微软 Azure 云区块链服务
    • 使用超级账本 Cello 搭建区块链服务
    • 本章小结
  • 性能与评测
    • 简介
    • Hyperledger Fabric v0.6
    • 小结
  • 附录
    • 术语
    • 常见问题
    • Go 语言开发相关
      • 安装与配置 Golang 环境
      • 编辑器与 IDE
      • 高效开发工具
      • 依赖管理
    • ProtoBuf 与 gRPC
    • 参考资源链接
由 GitBook 提供支持
在本页
  • ProtoBuf
  • gRPC
  • 实现服务端代码
  • 生成客户端代码

这有帮助吗?

在GitHub上编辑
  1. 附录

ProtoBuf 与 gRPC

上一页依赖管理下一页参考资源链接

最后更新于3年前

这有帮助吗?

是一套接口描述语言(),类似 Apache 的 。

相关处理工具主要是 ,基于 C++ 语言实现。

用户写好 .proto 描述文件,之后便可以使用 protoc 自动编译生成众多计算机语言(C++、Java、Python、C#、Go 等)的接口代码。这些代码可以支持 gRPC,也可以不支持。

是 Google 开源的 RPC 框架和库,已支持主流计算机语言。底层通信采用 HTTP2 协议,比较适合互联网场景。gRPC 在设计上考虑了跟 ProtoBuf 的配合使用。

两者分别解决不同问题,可以配合使用,也可以分开单独使用。

典型的配合使用场景是,写好 .proto 描述文件定义 RPC 的接口,然后用 protoc(带 gRPC 插件)基于 .proto 模板自动生成客户端和服务端的接口代码。

ProtoBuf

需要工具主要包括:

  • 编译工具:,以及一些官方没有带的语言插件;

  • 运行环境:各种语言的 protobuf 库,不同语言有不同的安装来源;

语法类似 C++ 语言,可以参考 ProtoBuf 语言规范:https://developers.google.com/protocol-buffers/docs/proto。

比较核心的,message 是代表数据结构(里面可以包括不同类型的成员变量,包括字符串、数字、数组、字典……),service 代表 RPC 接口。变量后面的数字是代表进行二进制编码时候的提示信息,1~15 表示热变量,会用较少的字节来编码。另外,支持导入。

默认所有变量都是可选的(optional),repeated 则表示数组。主要 service rpc 接口接受单个 message 参数,返回单个 message。

参考官方给出示例,如下所示:

syntax = "proto3";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

编译最关键的参数是输出语言格式参数,例如,python 为 --python_out=OUT_DIR。

一些还没有官方支持的语言,可以通过安装 protoc 对应的 plugin 来支持。例如,对于 Go 语言,可以安装

$ go get -u github.com/golang/protobuf/{protoc-gen-go,proto} // 前者是 plugin;后者是 go 的依赖库

之后,正常使用 protoc --go_out=./ ./hello.proto 命令调用 protoc-gen-go 插件来生成 hello.pb.go。

ProtoBuf 提供了 Marshal/Unmarshal 方法来将数据结构进行序列化操作。所生成的二进制文件在存储效率上比 XML 高 310 倍,并且处理性能高 12 个数量级。

gRPC

相关工具主要包括:

  • protoc,以及 gRPC 插件和其它插件:采用 ProtoBuf 作为 IDL 时,对 .proto 文件进行编译处理。

以上面 proto 文件为例,需要执行时添加 gRPC 的 plugin:

$ protoc --go_out=plugins=grpc:. hello.proto

执行后会生成对应的 .pb.go 文件,其中包括了 proto 文件中指定的结构和 protobuf 协议相关转换代码。

实现服务端代码

生成的 .pb.go 文件中,服务端相关的核心代码如下,主要定义了 GreeterServer 接口,用户可以自行修改或编写实现代码。

type GreeterServer interface {
    SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}

func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
    s.RegisterService(&_Greeter_serviceDesc, srv)
}

用户需要自行实现服务端接口,代码如下。

比较重要的,创建并启动一个 gRPC 服务的过程:

  • 创建监听套接字:lis, err := net.Listen("tcp", port);

  • 创建服务端:grpc.NewServer();

  • 注册服务:pb.RegisterGreeterServer();

  • 启动服务端:s.Serve(lis)。

package main

import (
    "context"
    "fmt"
    "log"
    "net"

    "google.golang.org/grpc"
    pb "hello/hello"
    )

const (
    port = ":50051"
)

type server struct{ }

// 这里实现服务端接口中的方法。
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Printf("Received: %v\n", in.GetName())
    return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

// 创建并启动一个 gRPC 服务的过程:创建监听套接字、创建服务端、注册服务、启动服务端。
func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
            log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &server{})
    fmt.Printf("Starting listen on port: %s", port)
    if err := s.Serve(lis); err != nil {
            log.Fatalf("failed to serve: %v", err)
    }
}

编译并启动服务端。

$ go run server/server.go
Starting listen on port: :50051

生成客户端代码

生成的 Go 文件中客户端相关代码如下,主要和实现了 HelloServiceClient 接口。用户可以通过 gRPC 来直接调用这个接口。

type GreeterClient interface {
    // Sends a greeting
    SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}

type greeterClient struct {
    cc *grpc.ClientConn
}

func NewGreeterClient(cc *grpc.ClientConn) GreeterClient {
    return &greeterClient{cc}
}

func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
    out := new(HelloReply)
    err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

用户直接调用接口方法:创建连接、创建客户端、调用接口。

package main

import (
    "context"
    "log"
    "os"
    "time"

    "google.golang.org/grpc"
    pb "hello/hello"
)

const (
    address     = "localhost:50051"
    defaultName = "world"
)

func main() {
    // Set up a connection to the server.
    conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
            log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewGreeterClient(conn)

    // Contact the server and print out its response.
    name := defaultName
    if len(os.Args) > 1 {
            name = os.Args[1]
    }
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
    if err != nil {
            log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.GetMessage())
}

编译并启动客户端,可以查看到服务端返回的消息。

$ go run client/client.go
Greeting: Hello world

运行时库:各种不同语言有不同的,主流语言的包管理器都已支持。

类似其它 RPC 框架,gRPC 的库在服务端提供一个 gRPC Server,客户端的库是 gRPC Stub。典型的场景是客户端发送请求,同步或异步调用服务端的接口。客户端和服务端之间的通信协议是基于 HTTP2 的 协议,支持双工的流式保序消息,性能比较好,同时也很轻。

采用 ProtoBuf 作为 IDL,则需要定义 service 类型。生成客户端和服务端代码。用户自行实现服务端代码中的调用接口,并且利用客户端代码来发起请求到服务端。一个完整的例子可以参考 。

gRPC 更多原理可以参考。

ProtoBuf
Interface Definition Language,IDL
Thrift
protoc
gRPC
protoc
安装方法
gRPC
https://github.com/grpc/grpc-go/blob/master/examples/helloworld
官方文档:http://www.grpc.io/docs