zoukankan      html  css  js  c++  java
  • gRPC —— 概览

    官网 地址:

    http://doc.oschina.net/grpc?t=56831

    https://www.grpc.io/docs/

    gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.

    gRPC 是什么?

    在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

    gRPC 客户端和服务端可以在多种环境中运行和交互 - 从 google 内部的服务器到你自己的笔记本,并且可以用任何 gRPC 支持的语言来编写。所以,你可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端。此外,Google 最新 API 将有 gRPC 版本的接口,使你很容易地将 Google 的功能集成到你的应用里。

    使用 protocol buffers

    gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON)。正如你将在下方例子里所看到的,你用 proto files 创建 gRPC 服务,用 protocol buffers 消息类型来定义方法参数和返回类型。你可以在 Protocol Buffers 文档找到更多关于 Protocol Buffers 的资料。

    Protocol buffers 版本

    尽管 protocol buffers 对于开源用户来说已经存在了一段时间,例子内使用的却一种名叫 proto3 的新风格的 protocol buffers,它拥有轻量简化的语法、一些有用的新功能,并且支持更多新语言。当前针对 Java 和 C++ 发布了 beta 版本,针对 JavaNano(即 Android Java)发布 alpha 版本,在protocol buffers Github 源码库里有 Ruby 支持, 在golang/protobuf Github 源码库里还有针对 Go 语言的生成器, 对更多语言的支持正在开发中。 你可以在 proto3 语言指南里找到更多内容, 在与当前默认版本的发布说明比较,看到两者的主要不同点。更多关于 proto3 的文档很快就会出现。虽然你可以使用 proto2 (当前默认的 protocol buffers 版本), 我们通常建议你在 gRPC 里使用 proto3,因为这样你可以使用 gRPC 支持全部范围的的语言,并且能避免 proto2 客户端与 proto3 服务端交互时出现的兼容性问题,反之亦然

    你好 gRPC!

    现在你已经对 gRPC 有所了解,了解其工作机制最简单的方法是看一个简单的例子。 Hello World 将带领你创建一个简单的客户端——服务端应用,向你展示:

    • 通过一个 protocol buffers 模式,定义一个简单的带有 Hello World 方法的 RPC 服务。
    • 用你最喜欢的语言(如果可用的话)来创建一个实现了这个接口的服务端。
    • 用你最喜欢的(或者其他你愿意的)语言来访问你的服务端。

    这个例子完整的代码在我们 GitHub 源码库的 examples 目录下。

    安装 gRPC

    针对你选择的语言构建和安装 gRPC 插件和相关工具,可以参照快速开始。 Java gRPC 除了 JDK 外不需要其他工具。

    ……

    • Python

    例子代码在 GitHub 源码库的 examples 目录。你可以运行如下命令克隆源码到本地:

    $ git clone https://github.com/grpc/grpc.git

    切换当前目录到 examples/python/helloworld

    $ cd examples/python/helloworld/

    • Go

    获取例子:

    $ go get -u github.com/grpc/grpc-go/examples/helloworld/greeter_client
    $ go get -u github.com/grpc/grpc-go/examples/helloworld/greeter_server
    

    切换当前目录到 examples/helloworld

    • C#

    例子代码在 GitHub 源码库的 examples 目录。你可以运行如下命令克隆源码到本地:

    $ git clone https://github.com/grpc/grpc。git

    从 Visual Studio (或 Linux 上的 Monodevelop ) 打开 Greeter.sln。可以从 C# Quickstart 找到平台特定的设置步骤。

    定义服务

    创建我们例子的第一步是定义一个服务:一个 RPC 服务通过参数和返回类型来指定可以远程调用的方法。就像你在 概览 里所看到的, gRPC 通过 protocol buffers 来实现。 我们使用 protocol buffers 接口定义语言来定义服务方法,用 protocol buffer 来定义参数和返回类型。客户端和服务端均使用服务定义生成的接口代码。 这里有我们服务定义的例子,在 helloworld.proto 里用 protocol buffers IDL 定义的。Greeter 服务有一个方法 SayHello ,可以让服务端从远程客户端接收一个包含用户名的 HelloRequest 消息后,在一个 HelloReply 里发送回一个 Greeter。这是你可以在 gRPC 里指定的最简单的 RPC - 你可以在教程里找到针对你选择的语言更多类型的例子。

    生成 gRPC 代码

    一旦定义好服务,我们可以使用 protocol buffer 编译器 protoc 来生成创建应用所需的特定客户端和服务端的代码 - 你可以生成任意 gRPC 支持的语言的代码,当然 PHP 和 Objective-C 仅支持创建客户端代码。生成的代码同时包括客户端的存根和服务端要实现的抽象接口,均包含 Greeter 所定义的方法。

    (假如你没有在系统里安装 gRPC 插件和 protoc ,并且仅仅是要看一下这个例子,你可以跳过这一步,直接到下一步来查看生成的代码。)

    • Python

    可以用如下命令生成客户端和服务端:

    $ ./run_codegen.sh
    

    这内部调用 protocol buffer 编译器:

    $ protoc -I ../../protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../../protos/helloworld.proto
    

    这生成了 helloworld_pb2.py ,包含我们生成的客户端和服务端类,此外还有用于填充、序列化、提取 HelloRequestHelloResponse 消息类型的类。

    • Go

    为了生成客户端和服务端接口,运行 protocol buffer 编译器:

    protoc -I ../protos ../protos/helloworld.proto --go_out=plugins=grpc:helloworld
    

    这生成了 helloworld.pb.go ,包含了我们生成的客户端和服务端类,此外还有用于填充、序列化、提取 HelloRequestHelloResponse 消息类型的类。

    • 在 Linux 或 OS X ,我们依赖通过 Linuxbrew 或者 Homebrew 安装的 protoc 和 grpc_csharp_plugin 。请在 route_guide 目录下运行这个命令:
      $ protoc -I../../protos --csharp_out Greeter --grpc_out Greeter --plugin=protoc-gen-grpc=`which grpc_csharp_plugin` ../../protos/helloworld.proto
    

    根据你的 OS 运行合适的命令,在 Greeter 目录重新生成如下文件:

    • Greeter/Helloworld.cs 定义了命名空间 Helloworld 它包含了所有用来填充、序列化、提取请求和应答消息类型的 protocol buffer 代码。
    • Greeter/HelloworldGrpc.cs,提供了存根类和服务类,包括:

      • 一个 Greeter.IGreeter 接口,可以在定义 RootGuide 服务实现的时候来继承它。
      • 一个 Greeter.GreeterClient 类,可用来访问远程的 RouteGuide 实例。

    写一个服务器

    现在让我们写点代码!首先我们将创建一个服务应用来实现服务(你会记起来,我们可以是使用除了Objective-C and PHP 外的其他所有语言来实现)。在本节,我们不打算对如何创建一个服务端进行更深入地探讨 —— 更详细的信息可以在你选择语言对应的教程里找到。

    服务实现

    ……

    Python

    greeter_server.py 实现了 Greeter 服务所需要的行为。 正如你所见,Greeter 类通过实现 sayHello 方法,实现了从 proto 服务定义生成的helloworld_pb2.BetaGreeterServicer 接口:

    class Greeter(helloworld_pb2.BetaGreeterServicer):
    
    def SayHello(self, request, context):
      return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
    

    为了返回给客户端应答并且完成调用:

    1. 用我们的激动人心的消息构建并填充一个在我们接口定义的 HelloReply 应答对象。
    2. 将 HelloReply 返回给客户端。

    Go

    greeter_server/main.go 实现了 Greeter 服务所需要的行为。 正如你所见,服务器有一个 server 结构。它通过实现 sayHello 方法,实现了从 proto 服务定义生成的GreeterServer 接口:

    // server is used to implement helloworld.GreeterServer.
    type server struct{}
    // SayHello implements helloworld.GreeterServer
    func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
      return &pb.HelloReply{Message: "Hello " + in.Name}, nil
    }
    

    为了返回给客户端应答并且完成调用:

    1. 用我们的激动人心的消息构建并填充一个在我们接口定义的 HelloReply 应答对象。
    2. 将 HelloReply 返回给客户端。

    Ruby

    greeter_server.rb 实现了 Greeter 服务所需要的行为。 服务器有一个 GreeterServer 类,它通过实现 sayHello 方法,实现了从 proto 服务定义生成的GreeterServer 接口:

    class GreeterServer < Helloworld::Greeter::Service
    # say_hello implements the SayHello rpc method.
    def say_hello(hello_req, _unused_call)
      Helloworld::HelloReply.new(message: "Hello #{hello_req.name}")
    end
    

    为了返回给客户端应答并且完成调用:我们用激动人心的消息构建并填充一个在我们接口定义的 HelloReply 应答对象,然后返回它。

    Node.js

    greeter_server.js 实现了 Greeter 服务所需要的行为。 服务器通过实现 SayHello 方法,实现了服务定义:

    function sayHello(call, callback) {
    callback(null, {message: 'Hello ' + call.request.name});
    }
    

    为了返回给客户端应答并完成调用,我们填充了应答并将其传递给一个已提供了的回调,用 null 作为第一个参数来表示没有出现错误。

    C#

    GreeterServer/Program.cs 实现了 Greeter 服务所需要的行为。 服务器的 GreeterImpl类,通过实现 sayHello 方法,实现了生成的IGreeter 接口:

    class GreeterImpl : Greeter.IGreeter
    {
      public Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
      {
          return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
      }
    }
    

    为了返回给客户端应答并完成以下调用:

    1. 用我们的激动人心的消息构建并填充一个在我们接口定义的 HelloReply 应答对象。
    2. 将 HelloReply 返回给客户端。

    服务端实现

    需要提供一个 gRPC 服务的另一个主要功能是让这个服务实在在网络上可用。

    ……

    Python

    greeter_server.py 提供了以下代码作为 Python 的例子。

    server = helloworld_pb2.beta_create_Greeter_server(Greeter())
    server.add_insecure_port('[::]:50051')
    server.start()
    try:
      while True:
        time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
      server.stop()

    Go

    greeter_server/main.go 提供了以下代码作为 Go 的例子。

    const (
      port = ":50051"
    )
    ...
    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{})
      s.Serve(lis)
    }

    Ruby

    greeter_server.rb 提供了以下代码作为 Ruby 的例子。

    def main
    s = GRPC::RpcServer.new
    s.add_http2_port('0.0.0.0:50051')
    s.handle(GreeterServer)
    s.run
    end

    Node.js

    greeter_server.js 提供了以下代码作为 Ruby 的例子。

    function main() {
    var server = new Server({
      "helloworld.Greeter": {
        sayHello: sayHello
      }
    });
    server.bind('0.0.0.0:50051');
    server.listen();
    }
    • C#

      GreeterServer/Program.cs 提供了以下代码作为 C# 的例子。

      Server server = new Server
      {
        Services = { Greeter.BindService(new GreeterImpl()) },
        Ports = { new ServerPort("localhost", 50051, ServerCredentials.Insecure) }
      };
      server.Start();
      

    在这里我们创建了合理的 gRPC 服务器,将我们实现的 Greeter 服务绑定到一个端口。然后我们启动服务器:服务器现在已准备好从 Greeter 服务客户端接收请求。我们将在具体语言对应的文档里更深入地了解这所有的工作是怎样进行的。

    写一个客户端

    客户端的 gRPC 非常简单。在这一步,我们将用生成的代码写一个简单的客户程序来访问我们在上一节里创建的 Greeter 服务器。 同样,我们也不打算对如何实现一个客户端程序深入更多,我们把这些内容放到教程里。

    连接服务

    首先我们看一下我们如何连接 Greeter 服务器。我们需要创建一个 gRPC 频道,指定我们要连接的主机名和服务器端口。然后我们用这个频道创建存根实例。

    Python

    生成的 Python 代码有一个根据频道创建存根的帮助方法。

    channel = implementations.insecure_channel('localhost', 50051)
    stub = helloworld_pb2.beta_create_Greeter_stub(channel)
    ...

    Go

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

    在 gRPC Go 你是使用一个特殊的 Dial() 方法来创建频道。

    Ruby

    stub = Helloworld::Greeter::Stub.new('localhost:50051')

    在 Ruby 里,我们可以在一个方法里调用从 .proto 文件里生成的存根类。

    Node.js

    var client = new hello_proto.Greeter('localhost:50051');

    在 Node.js ,我们可以在一步调用 Greeter 存根构造器。

    C#

    Channel channel = new Channel("127.0.0.1:50051", Credentials.Insecure);
    var client = Greeter.NewClient(channel);
    ...

    调用 RPC

    现在我们可以联系服务并获得一个 greeting :

    1. 我们创建并填充一个 HelloRequest 发送给服务。
    2. 我们用请求调用存根的 SayHello(),如果 RPC 成功,会得到一个填充的 HelloReply ,从其中我们可以获得 greeting。
    • Python

      response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS)
      print "Greeter client received: " + response.message
      

      你可以在 greeter_client.py 里查看完整的客户端代码。

    • Go

      r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
      if err != nil {
            log.Fatalf("could not greet: %v", err)
      }
      log.Printf("Greeting: %s", r.Message)
      

      你可以在 greeter_client/main.go 里查看完整的客户端代码。

    Ruby

    message = stub.say_hello(Helloworld::HelloRequest.new(name: user)).message
    p "Greeting: #{message}"
    

    你可以在 greeter_client.rb 里查看完整的客户端代码。

    • Node.js

     client.sayHello({name: user}, function(err, response) {
        console.log('Greeting:', response.message);
      });
    

    你可以在 /examples/node/greeter_client.js 里查看完整的客户端代码。

    C#

    var reply = client.SayHello(new HelloRequest { Name = user });
    Console.WriteLine("Greeting: " + reply.Message);
    

    你可以在 GreeterClient/Program.cs 里查看完整的客户端代码。

    • PHP

      $request = new helloworldHelloRequest();
      $request->setName($name);
      list($reply, $status) = $client->SayHello($request)->wait();
      $message = $reply->getMessage();
    

    你可以在greeter_client.php 里查看完整的客户端代码。

    试一下!

    你可以尝试用同一个语言在客户端和服务端构建并运行例子。

    或者你可以尝试 gRPC 最有用的一个功能 - 不同的语言间的互操作性,即在不同的语言运行客户端和服务端。

    每个服务端和客户端使用从同一过 proto 文件生成的接口代码,则意味着任何 Greeter 客户端可以与任何 Greeter 服务端对话。

    • Python 你可以用如下命令到 examples/python/helloworld 下运行服务端:

      $ ./run_server.sh

    • Go

      你可以用如下命令到 examples/helloworld 下运行服务端:

      $ greeter_server &

    • Ruby

      你可以用如下命令到 examples/ruby 下运行服务端:

      $ bundle exec ./greeter_server.rb &

    • Node.js 你可以用如下命令到 examples/node 下运行服务端:

      $ node ./greeter_server.js &

    • C# 构建解决方案,然后到 examples/csharp

    > cd GreeterServer/bin/Debug
    > GreeterServer.exe
    

    一旦服务器在运行,在其他的终端窗口运行客户端并确认它收到一个消息。

    • Python

      你可以从examples/python/helloworld目录下用如下命令运行客户端: $ ./run_client.sh

    • Go

      你可以从examples/helloworld目录下用如下命令运行客户端:

      $ greeter_client

    • Ruby

      你可以从examples/node目录下用如下命令运行客户端: $ bundle exec ./greeter_client.rb

    • Node.js

      你可以从examples/node目录下用如下命令运行客户端:

      $ node ./greeter_client.js

    • C#

      构建解决方案,然后从 examples/csharp 目录:

      > cd GreeterClient/bin/Debug
      > GreeterClient.exe

    更多资料!

    • 快速开始找到如何安装 gRPC 并从每个语言开始 。
    • 按照你喜欢的语言对应教程来学习。
    •  gRPC 概念发现更多包括 RPC 生命周期,同步、异步调用,过期时间等内容。
    • 读一下 HTTP2协议上的 gRPC 里的详细描述
    • gRPC 认证支持里则介绍了 gRPC 对认证支持的机制和例子。
  • 相关阅读:
    [SCOI2009] Windy数
    [P1361] 小M的作物
    Wannafly Camp 2020 Day 2E 阔力梯的树
    2017百越杯反序列化writeup
    大美西安writeup
    Thinkphp的SQL查询方式
    Thinkphp的CURD
    记一次拿webshell踩过的坑(如何用PHP编写一个不包含数字和字母的后门)
    ThinkPHP的输出和模型使用
    ThinkPHP的运行流程-2
  • 原文地址:https://www.cnblogs.com/panpanwelcome/p/13492392.html
Copyright © 2011-2022 走看看