Golang gRPC 使用

Stella981
• 阅读 798

一、概念

1、gRPC默认使用protocol buffers,这是google开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如JSON),可以用proto files创建gRPC服务,用protocol buffers消息类型来定义方法参数和返回类型。

二、安装

1、yum install autoconf automake libtool  (centos 系统)

2、protocal buffer安装

从 https://github.com/google/protobuf/releases下载安装包,解压,然后操作以下命令:

./autogen.sh
./configure
make
make install

最后设置环境变量即可:export LD_LIBRARY_PATH=/usr/local/lib

Golang gRPC 使用

3、安装 golang protobuf

go get -u github.com/golang/protobuf/proto // golang protobuf 库
go get -u github.com/golang/protobuf/protoc-gen-go //protoc --go_out 工具

4、安装 gRPC-go

go get google.golang.org/grpc

无法下载的话去 https://github.com/grpc/grpc-go 下载

三、使用

1、编写 proto 文件,helloworld.proto

syntax = "proto3";

option objc_class_prefix = "HLW";

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;
}
  • syntax="proto3":指定protobuf的版本
  • package helloworld_:声明一个报名,一般与文件目录名相同_
  • import "xxx/xx.proto":导入其他的包,这样你就可以使用其他的包的数据结构
  • required、optional、repeated:表示该字段是否必须填充;required表示必须指定且只能指定一个;当optional表示可选,可指定也可不指定,但不可超过一个不指定值的时候会采用空值,如string类型的字段会用字符串表示;repeated表示可以重复,类似与编程语言中的list
  • message Author:在一个message体内定义一个message结构体
  • enum:是枚举类型结构体
  • 数字:字段的标识符,不可重复
  • 数据类型: int32、int64、uint32、uint64、sint32、sint64、double、float、 string、bool、bytes、enum、message等等

2、使用protoc命令生成相关文件:

protoc --go_out=plugins=grpc:. helloworld.proto
ls
helloworld.pb.go    helloworld.proto

这里用了plugins选项,提供对grpc的支持,否则不会生成Service的接口,方便编写服务器和客户端程序

helloworld.pb.go 文件如下:

Golang gRPC 使用 Golang gRPC 使用

  1 // Code generated by protoc-gen-go. DO NOT EDIT.
  2 // source: helloworld.proto
  3 
  4 package helloworld
  5 
  6 import (
  7     context "context"
  8     fmt "fmt"
  9     proto "github.com/golang/protobuf/proto"
 10     grpc "google.golang.org/grpc"
 11     math "math"
 12 )
 13 
 14 // Reference imports to suppress errors if they are not otherwise used.
 15 var _ = proto.Marshal
 16 var _ = fmt.Errorf
 17 var _ = math.Inf
 18 
 19 // This is a compile-time assertion to ensure that this generated file
 20 // is compatible with the proto package it is being compiled against.
 21 // A compilation error at this line likely means your copy of the
 22 // proto package needs to be updated.
 23 const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
 24 
 25 // The request message containing the user's name.
 26 type HelloRequest struct {
 27     Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
 28     XXX_NoUnkeyedLiteral struct{} `json:"-"`
 29     XXX_unrecognized     []byte   `json:"-"`
 30     XXX_sizecache        int32    `json:"-"`
 31 }
 32 
 33 func (m *HelloRequest) Reset()         { *m = HelloRequest{} }
 34 func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
 35 func (*HelloRequest) ProtoMessage()    {}
 36 func (*HelloRequest) Descriptor() ([]byte, []int) {
 37     return fileDescriptor_17b8c58d586b62f2, []int{0}
 38 }
 39 
 40 func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
 41     return xxx_messageInfo_HelloRequest.Unmarshal(m, b)
 42 }
 43 func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
 44     return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
 45 }
 46 func (m *HelloRequest) XXX_Merge(src proto.Message) {
 47     xxx_messageInfo_HelloRequest.Merge(m, src)
 48 }
 49 func (m *HelloRequest) XXX_Size() int {
 50     return xxx_messageInfo_HelloRequest.Size(m)
 51 }
 52 func (m *HelloRequest) XXX_DiscardUnknown() {
 53     xxx_messageInfo_HelloRequest.DiscardUnknown(m)
 54 }
 55 
 56 var xxx_messageInfo_HelloRequest proto.InternalMessageInfo
 57 
 58 func (m *HelloRequest) GetName() string {
 59     if m != nil {
 60         return m.Name
 61     }
 62     return ""
 63 }
 64 
 65 // The response message containing the greetings
 66 type HelloReply struct {
 67     Message              string   `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
 68     XXX_NoUnkeyedLiteral struct{} `json:"-"`
 69     XXX_unrecognized     []byte   `json:"-"`
 70     XXX_sizecache        int32    `json:"-"`
 71 }
 72 
 73 func (m *HelloReply) Reset()         { *m = HelloReply{} }
 74 func (m *HelloReply) String() string { return proto.CompactTextString(m) }
 75 func (*HelloReply) ProtoMessage()    {}
 76 func (*HelloReply) Descriptor() ([]byte, []int) {
 77     return fileDescriptor_17b8c58d586b62f2, []int{1}
 78 }
 79 
 80 func (m *HelloReply) XXX_Unmarshal(b []byte) error {
 81     return xxx_messageInfo_HelloReply.Unmarshal(m, b)
 82 }
 83 func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
 84     return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic)
 85 }
 86 func (m *HelloReply) XXX_Merge(src proto.Message) {
 87     xxx_messageInfo_HelloReply.Merge(m, src)
 88 }
 89 func (m *HelloReply) XXX_Size() int {
 90     return xxx_messageInfo_HelloReply.Size(m)
 91 }
 92 func (m *HelloReply) XXX_DiscardUnknown() {
 93     xxx_messageInfo_HelloReply.DiscardUnknown(m)
 94 }
 95 
 96 var xxx_messageInfo_HelloReply proto.InternalMessageInfo
 97 
 98 func (m *HelloReply) GetMessage() string {
 99     if m != nil {
100         return m.Message
101     }
102     return ""
103 }
104 
105 func init() {
106     proto.RegisterType((*HelloRequest)(nil), "helloworld.HelloRequest")
107     proto.RegisterType((*HelloReply)(nil), "helloworld.HelloReply")
108 }
109 
110 func init() { proto.RegisterFile("helloworld.proto", fileDescriptor_17b8c58d586b62f2) }
111 
112 var fileDescriptor_17b8c58d586b62f2 = []byte{
113     // 149 bytes of a gzipped FileDescriptorProto
114     0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9,
115     0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x88,
116     0x28, 0x29, 0x71, 0xf1, 0x78, 0x80, 0x78, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42,
117     0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92,
118     0x1a, 0x17, 0x17, 0x54, 0x4d, 0x41, 0x4e, 0xa5, 0x90, 0x04, 0x17, 0x7b, 0x6e, 0x6a, 0x71, 0x71,
119     0x62, 0x3a, 0x4c, 0x11, 0x8c, 0x6b, 0xe4, 0xc9, 0xc5, 0xee, 0x5e, 0x94, 0x9a, 0x5a, 0x92, 0x5a,
120     0x24, 0x64, 0xc7, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0xd6, 0x25, 0x24, 0xa1, 0x87, 0xe4, 0x02, 0x64,
121     0xcb, 0xa4, 0xc4, 0xb0, 0xc8, 0x14, 0xe4, 0x54, 0x2a, 0x31, 0x38, 0xb1, 0x2d, 0x62, 0x62, 0xf6,
122     0xf0, 0x09, 0x4f, 0x62, 0x03, 0xbb, 0xd8, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0xbe, 0xde, 0x1d,
123     0x2e, 0xc5, 0x00, 0x00, 0x00,
124 }
125 
126 // Reference imports to suppress errors if they are not otherwise used.
127 var _ context.Context
128 var _ grpc.ClientConn
129 
130 // This is a compile-time assertion to ensure that this generated file
131 // is compatible with the grpc package it is being compiled against.
132 const _ = grpc.SupportPackageIsVersion4
133 
134 // GreeterClient is the client API for Greeter service.
135 //
136 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
137 type GreeterClient interface {
138     // Sends a greeting
139     SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
140 }
141 
142 type greeterClient struct {
143     cc *grpc.ClientConn
144 }
145 
146 func NewGreeterClient(cc *grpc.ClientConn) GreeterClient {
147     return &greeterClient{cc}
148 }
149 
150 func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
151     out := new(HelloReply)
152     err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...)
153     if err != nil {
154         return nil, err
155     }
156     return out, nil
157 }
158 
159 // GreeterServer is the server API for Greeter service.
160 type GreeterServer interface {
161     // Sends a greeting
162     SayHello(context.Context, *HelloRequest) (*HelloReply, error)
163 }
164 
165 func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
166     s.RegisterService(&_Greeter_serviceDesc, srv)
167 }
168 
169 func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
170     in := new(HelloRequest)
171     if err := dec(in); err != nil {
172         return nil, err
173     }
174     if interceptor == nil {
175         return srv.(GreeterServer).SayHello(ctx, in)
176     }
177     info := &grpc.UnaryServerInfo{
178         Server:     srv,
179         FullMethod: "/helloworld.Greeter/SayHello",
180     }
181     handler := func(ctx context.Context, req interface{}) (interface{}, error) {
182         return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
183     }
184     return interceptor(ctx, in, info, handler)
185 }
186 
187 var _Greeter_serviceDesc = grpc.ServiceDesc{
188     ServiceName: "helloworld.Greeter",
189     HandlerType: (*GreeterServer)(nil),
190     Methods: []grpc.MethodDesc{
191         {
192             MethodName: "SayHello",
193             Handler:    _Greeter_SayHello_Handler,
194         },
195     },
196     Streams:  []grpc.StreamDesc{},
197     Metadata: "helloworld.proto",
198 }

View Code

3、服务器程序

package main

import (
    "log"
    "net"

    pb "test_grpc/helloworld"
    "google.golang.org/grpc"
    "golang.org/x/net/context"
)

const (
    PORT = ":50001"
)

type server struct {}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Println("request: ", in.Name)
    return &pb.HelloReply{Message: "Hello " + in.Name}, 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{})
    log.Println("rpc服务已经开启")
    s.Serve(lis)
}

4、客户端程序

package main

import (
    "log"
    "os"

    pb "test_grpc/helloworld"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
)

const (
    address = "localhost:50001"
)

func main() {
    conn, err := grpc.Dial(address, grpc.WithInsecure())

    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }

    defer conn.Close()

    c := pb.NewGreeterClient(conn)

    name := "lin"
    if len(os.Args) > 1 {
        name = os.Args[1]
    }

    r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})

    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }

    log.Println(r.Message)
}
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这