gRPC应用golang

1. gRPC简述

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

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

gRPC默认使用protocol buffers作为交换数据序列化的机制,即gRPC底层依赖protobuf。

2. gRPC-go安装

1)安装protobuf编译器protoc,可直接从<https://github.com/protocolbuffers/protobuf/releases&gt;安装稳定版本

2)安装golang插件protoc-gen-go。

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

3)下载grpc-go仓库

grpc-go仓库原地址为:google.golang.org/grpc,由于原地址屏蔽,需要从github拉下来后拷贝到$GOPATH/old-src/google.golang.org/grpc。

git clone https://github.com/grpc/grpc-go.git $GOPATH/old-src/google.golang.org/grpc

4)配置goproxy,在/etc/profile最后加上如下代码后source。

export GO111MODULE=on
export GOPROXY=&quot;https://goproxy.cn&quot;

5)直接编译例程

$ go get google.golang.org/grpc/examples/helloworld/greeter_client
$ go get google.golang.org/grpc/examples/helloworld/greeter_server

编译成功后可执行文件位于$GOPATH/bin下。

3. gRPC-go应用

1 定义服务

一个 RPC 服务通过参数和返回类型来指定可以远程调用的方法。gRPC通过protobuf来实现。

使用 protocol buffers 接口定义语言来定义服务方法,用 protocol buffer 来定义参数和返回类型。客户端和服务端均使用服务定义生成的接口代码。

syntax = &quot;proto3&quot;;

option java_package = &quot;io.grpc.examples&quot;;

package helloworld;

// The greeter 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;
}

2. 生成gRPC代码

使用protoc来生成创建应用所需的特定客户端和服务端的代码,文件*.pb.go。生成的代码同时包括客户端的存根和服务端要实现的抽象接口,均包含Greeter所定义的方法。

进入helloworld.proto所在目录:

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

注意:生成兼容gRPC代码。

若protoc文件指定了RPC services,protoc-gen-go可以生成兼容gRPC的代码,需要指定go_out的plugins参数,常用方法如下:

If a proto file specifies RPC services, protoc-gen-go can be instructed to generate code compatible with gRPC (<http://www.grpc.io/&gt;). To do this, pass the plugins parameter to protoc-gen-go; the usual way is to insert it into the --go_out argument to protoc:

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

若不指定plugins=grpc参数,则生成的*.pb.go仅包含protobuf相关的代码,不包含grpc相关代码。

注意:插件参数列表

插件参数列表用逗号(,)分割,插件参数与输出路径用冒号(:)分隔。

To pass extra parameters to the plugin, use a comma-separated parameter list separated from the output directory by a colon:

protoc --go_out=plugins=grpc,import_path=mypackage:. *.proto
  • paths=(import | source_relative) - specifies how the paths of generated files are structured. See the "Packages and imports paths" section above. The default is import.
  • plugins=plugin1+plugin2 - specifies the list of sub-plugins to load. The only plugin in this repo is grpc.
  • Mfoo/bar.proto=quux/shme - declares that foo/bar.proto is associated with Go package quux/shme. This is subject to the import_prefix parameter.

The following parameters are deprecated and should not be used:

  • import_prefix=xxx - a prefix that is added onto the beginning of all imports.
  • import_path=foo/bar - used as the package if no input files declare go_package. If it contains slashes, everything up to the rightmost slash is ignored.

3. server端

服务器有一个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 &amp;pb.HelloReply{Message: &quot;Hello &quot; + in.Name}, nil 
}

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

const ( 
    port = &quot;:50051&quot; 
)
 ... 
func main() {
   lis, err := net.Listen(&quot;tcp&quot;, port) 
   if err != nil { 
        log.Fatalf(&quot;failed to listen: %v&quot;, err) 
   } 
   s := grpc.NewServer() pb.RegisterGreeterServer(s, &amp;server{}) 
   s.Serve(lis) 
}

详细代码如下:

package main

import (
    &quot;context&quot;
    &quot;log&quot;
    &quot;net&quot;

    &quot;google.golang.org/grpc&quot;
    pb &quot;google.golang.org/grpc/examples/helloworld/helloworld&quot;
)

const (
    port = &quot;:50051&quot;
)

// server is used to implement helloworld.GreeterServer.
type server struct {
    pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Printf(&quot;Received: %v&quot;, in.GetName())
    return &amp;pb.HelloReply{Message: &quot;Hello &quot; + in.GetName()}, nil
}

func main() {
    lis, err := net.Listen(&quot;tcp&quot;, port)
    if err != nil {
        log.Fatalf(&quot;failed to listen: %v&quot;, err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &amp;server{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf(&quot;failed to serve: %v&quot;, err)
    }
}

4. client端

// Package main implements a client for Greeter service.
package main

import (
    &quot;context&quot;
    &quot;log&quot;
    &quot;os&quot;
    &quot;time&quot;

    &quot;google.golang.org/grpc&quot;
    pb &quot;google.golang.org/grpc/examples/helloworld/helloworld&quot;
)

const (
    address     = &quot;localhost:50051&quot;
    defaultName = &quot;world&quot;
)

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

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

参考:

1. gRPC 官方文档中文版 <http://doc.oschina.net/grpc?t=56831&gt;

2. gRPC in 3 minutes (Go) <https://github.com/grpc/grpc-go/tree/master/examples&gt;

3. <https://github.com/golang/protobuf&gt;

4. gRPC应用C++

声明:该文章系转载,转载该文章的目的在于更广泛的传递信息,并不代表本网站赞同其观点,文章内容仅供参考。

本站是一个个人学习和交流平台,网站上部分文章为网站管理员和网友从相关媒体转载而来,并不用于任何商业目的,内容为作者个人观点, 并不代表本网站赞同其观点和对其真实性负责。

我们已经尽可能的对作者和来源进行了通告,但是可能由于能力有限或疏忽,导致作者和来源有误,亦可能您并不期望您的作品在我们的网站上发布。我们为这些问题向您致歉,如果您在我站上发现此类问题,请及时联系我们,我们将根据您的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。