带入gRPC:gRPC Client and Server

栏目: 服务器 · 发布时间: 6年前

内容简介:原文地址:本章节将使用 Go 来编写 gRPC Server 和 Client,让其互相通讯。在此之上会使用到如下库:检查是否安装成功

带入gRPC:gRPC Client and Server

原文地址: 带入gRPC:gRPC Client and Server

前言

本章节将使用 Go 来编写 gRPC Server 和 Client,让其互相通讯。在此之上会使用到如下库:

  • google.golang.org/grpc
  • github.com/golang/protobuf/protoc-gen-go

安装

gRPC

go get -u google.golang.org/grpc

Protocol Buffers v3

wget https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-all-3.5.1.zip
unzip protobuf-all-3.5.1.zip
cd protobuf-3.5.1/
./configure
make
make install

检查是否安装成功

protoc --version

若出现以下错误,执行 ldconfig 命名就能解决这问题

protoc: error while loading shared libraries: libprotobuf.so.15: cannot open shared object file: No such file or directory

Protoc Plugin

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

安装环境若有问题,可参考我先前的文章 《介绍与环境安装》 内有详细介绍,不再赘述

gRPC

本小节开始正式编写 gRPC 相关的程序,一起上车吧 :smile:

目录结构

$ tree go-grpc-example 
go-grpc-example
├── client
├── proto
│   └── search.proto
└── server.go

IDL

编写

在 proto 文件夹下的 search.proto 文件中,写入如下内容:

syntax = "proto3";

package proto;

service SearchService {
    rpc Search(SearchRequest) returns (SearchResponse) {}
}

message SearchRequest {
    string request = 1;
}

message SearchResponse {
    string response = 1;
}

生成

在 proto 文件夹下执行如下命令:

$ protoc --go_out=plugins=grpc:. *.proto
  • plugins=plugin1+plugin2:指定要加载的子插件列表

我们定义的 proto 文件是涉及了 RPC 服务的,而默认是不会生成 RPC 代码的,因此需要给出 plugins 参数传递给 protoc-gen-go ,告诉它,请支持 RPC(这里指定了 gRPC)

  • --go_out=.:设置 Go 代码输出的目录

该指令会加载 protoc-gen-go 插件达到生成 Go 代码的目的,生成的文件以 .pb.go 为文件后缀

  • : (冒号)

冒号充当分隔符的作用,后跟所需要的参数集。如果这处不涉及 RPC,命令可简化为:

$ protoc --go_out=. *.proto

注:建议你看看两条命令生成的 .pb.go 文件,分别有什么区别

生成后

执行完毕命令后,将得到一个 .pb.go 文件,文件内容如下:

type SearchRequest struct {
    Request              string   `protobuf:"bytes,1,opt,name=request" json:"request,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

func (m *SearchRequest) Reset()         { *m = SearchRequest{} }
func (m *SearchRequest) String() string { return proto.CompactTextString(m) }
func (*SearchRequest) ProtoMessage()    {}
func (*SearchRequest) Descriptor() ([]byte, []int) {
    return fileDescriptor_search_8b45f79ee13ff6a3, []int{0}
}

func (m *SearchRequest) GetRequest() string {
    if m != nil {
        return m.Request
    }
    return ""
}

通过阅读这一部分代码,可以知道主要涉及如下方面:

  • 字段名称从小写下划线转换为大写驼峰模式(字段导出)
  • 生成一组 Getters 方法,能便于处理一些空指针取值的情况
  • ProtoMessage 方法实现 proto.Message 的接口
  • 生成 Rest 方法,便于将 Protobuf 结构体恢复为零值
  • Repeated 转换为切片
type SearchRequest struct {
    Request              string   `protobuf:"bytes,1,opt,name=request" json:"request,omitempty"`
}

func (*SearchRequest) Descriptor() ([]byte, []int) {
    return fileDescriptor_search_8b45f79ee13ff6a3, []int{0}
}

type SearchResponse struct {
    Response             string   `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"`
}

func (*SearchResponse) Descriptor() ([]byte, []int) {
    return fileDescriptor_search_8b45f79ee13ff6a3, []int{1}
}

...

func init() { proto.RegisterFile("search.proto", fileDescriptor_search_8b45f79ee13ff6a3) }

var fileDescriptor_search_8b45f79ee13ff6a3 = []byte{
    // 131 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x4e, 0x4d, 0x2c,
    0x4a, 0xce, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x4a, 0x9a, 0x5c, 0xbc,
    0xc1, 0x60, 0xe1, 0xa0, 0xd4, 0xc2, 0xd2, 0xd4, 0xe2, 0x12, 0x21, 0x09, 0x2e, 0xf6, 0x22, 0x08,
    0x53, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, 0x55, 0xd2, 0xe1, 0xe2, 0x83, 0x29, 0x2d,
    0x2e, 0xc8, 0xcf, 0x2b, 0x4e, 0x15, 0x92, 0xe2, 0xe2, 0x28, 0x82, 0xb2, 0xa1, 0x8a, 0xe1, 0x7c,
    0x23, 0x0f, 0x98, 0xc1, 0xc1, 0xa9, 0x45, 0x65, 0x99, 0xc9, 0xa9, 0x42, 0xe6, 0x5c, 0x6c, 0x10,
    0x01, 0x21, 0x11, 0x88, 0x13, 0xf4, 0x50, 0x2c, 0x96, 0x12, 0x45, 0x13, 0x85, 0x98, 0xa3, 0xc4,
    0x90, 0xc4, 0x06, 0x16, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf3, 0xba, 0x74, 0x95, 0xc0,
    0x00, 0x00, 0x00,
}

而这一部分代码主要是围绕 fileDescriptor 进行,在这里 fileDescriptor_search_8b45f79ee13ff6a3 表示一个编译后的 proto 文件,而每一个方法都包含 Descriptor 方法,代表着这一个方法在 fileDescriptor 中具体的 Message Field

Server

这一小节将编写 gRPC Server 的基础模板,完成一个方法的调用。对 server.go 写入如下内容:

package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"

    pb "github.com/EDDYCJY/go-grpc-example/proto"
)

type SearchService struct{}

func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
    return &pb.SearchResponse{Response: r.GetRequest() + " Server"}, nil
}

const PORT = "9001"

func main() {
    server := grpc.NewServer()
    pb.RegisterSearchServiceServer(server, &SearchService{})

    lis, err := net.Listen("tcp", ":"+PORT)
    if err != nil {
        log.Fatalf("net.Listen err: %v", err)
    }

    server.Serve(lis)
}
  • 创建 gRPC Server 对象,你可以理解为它是 Server 端的抽象对象
  • 将 SearchService(其包含需要被调用的服务端接口)注册到 gRPC Server 的内部注册中心。这样可以在接受到请求时,通过内部的服务发现,发现该服务端接口并转接进行逻辑处理
  • 创建 Listen,监听 TCP 端口
  • gRPC Server 开始 lis.Accept,直到 Stop 或 GracefulStop

Client

接下来编写 gRPC Go Client 的基础模板,打开 client/client.go 文件,写入以下内容:

package main

import (
    "context"
    "log"

    "google.golang.org/grpc"

    pb "github.com/EDDYCJY/go-grpc-example/proto"
)

const PORT = "9001"

func main() {
    conn, err := grpc.Dial(":"+PORT, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("grpc.Dial err: %v", err)
    }
    defer conn.Close()

    client := pb.NewSearchServiceClient(conn)
    resp, err := client.Search(context.Background(), &pb.SearchRequest{
        Request: "gRPC",
    })
    if err != nil {
        log.Fatalf("client.Search err: %v", err)
    }

    log.Printf("resp: %s", resp.GetResponse())
}
  • 创建与给定目标(服务端)的连接交互
  • 创建 SearchService 的客户端对象
  • 发送 RPC 请求,等待同步响应,得到回调后返回响应结果
  • 输出响应结果

验证

启动 Server

$ pwd
$GOPATH/github.com/EDDYCJY/go-grpc-example
$ go run server.go

启动 Client

$ pwd             
$GOPATH/github.com/EDDYCJY/go-grpc-example/client
$ go run client.go 
2018/09/23 11:06:23 resp: gRPC Server

系列目录

总结

在本章节,我们对 Protobuf、gRPC Client/Server 分别都进行了介绍。希望你结合文中讲述内容再写一个 Demo 进行深入了解,肯定会更棒


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

虚拟现实:最后的传播

虚拟现实:最后的传播

聂有兵 / 中国发展出版社 / 2017-4-1 / 39.00

本书对“虚拟现实”这一诞生自70年代却在今天成为热门话题的概念进行了历史发展式的分析和回顾,认为虚拟现实是当今最重大的社会变革的技术因素之一,对虚拟现实在未来百年可能给人类社会的各个层面带来的影响进行说明,结合多个大众媒介的发展趋势,合理地推演未来虚拟现实在政治、经济、文化等领域的态势,并基于传播学理论框架提出了几个新的观点。对于普通读者,本书可以普及一般的虚拟现实知识;对于传媒行业,本书可以引导......一起来看看 《虚拟现实:最后的传播》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具