gRPC应用golang

Posted embedded-linux

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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安装稳定版本。

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/src/google.golang.org/grpc。

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

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

export GO111MODULE=on
export GOPROXY="https://goproxy.cn"

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 = "proto3";

option java_package = "io.grpc.examples";

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/). 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 &pb.HelloReply{Message: "Hello " + in.Name}, nil 
}

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

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) 
}

详细代码如下:

package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"
    pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

const (
    port = ":50051"
)

// 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("Received: %v", in.GetName())
    return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

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{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

4. client端

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

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

    "google.golang.org/grpc"
    pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

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())
}

 

参考:

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

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

3.   https://github.com/golang/protobuf

4.   gRPC应用C++

以上是关于gRPC应用golang的主要内容,如果未能解决你的问题,请参考以下文章

golang下grpc的实践

Golang gRPC 示例

GoLang -- gRPC框架四大服务

gRPC最佳入门教程,Golang/Python/PHP多语言讲解

grpc应用之二 gRPC使用

读golang的grpc源码