目录

创建Proto文件

生成proto文件对应的go文件

创建服务结构体

创建客户端测试

小结


学习笔记,写到哪是哪。

上一篇是写的redis操作来着,最近主要研究了一下grpc。

在玩grpc的过程中还是有点有意思的事。

关于grpc的相关原理,其他文章应该介绍的特别多了,我不赘述了。

发一下官方文档地址:Introduction to gRPC | gRPC

从官方给出的概览可以获得几个信息,一个是交互逻辑,一个是支持多种语言。别小看第二点,还是蛮重要的。

 数据的交互主要使用protocol buffers序列化结构,它可以转化为json,使用的原因主要是因为压缩的数据更小、传输速率更高。

好了,不多看了,看看我写的样例代码。

创建Proto文件

在项目里面先创建一个.proto文件,文件代码如下:

syntax = "proto3";
option go_package = "./proto";service Register {rpc TestRegister (RegisterMessage) returns (RegisterResponse){}
}message RegisterMessage{int32 id = 1;string name = 2;string info = 3;
}message RegisterResponse{string response = 1;
}

简单说明一下,定义了一个RegisterMessage结构体作为客户端连接发送过来的注册消息。

定义了一个注册回复消息,也就是RegisterResponse。

定义了一个rpc的接口TestRegister,也就是需要实现的功能。

生成proto文件对应的go文件

需要下载一个proto生成工具,地址:Releases · protocolbuffers/protobuf · GitHub

你要是嫌麻烦,可以下载我的网盘地址,如下:

链接:https://pan.baidu.com/s/1_frwb7vo_C2vIvQjJxneAA 
提取码:tuan

先看一下我项目结构。

OK,在工具包下cmd打开,执行下面的命令。

C:\Users\xxxx\Desktop\protoc-21.2-win64\bin\protoc.exe -I proto message.proto --go_out=plugins=grpc:.

这里注意一下,需要加上plugins=grpc,不然生成的文件中不带需要实现的接口。

文件内容如下:

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//  protoc-gen-go v1.28.0
//  protoc        v3.21.2
// source: message.protopackage protoimport (context "context"grpc "google.golang.org/grpc"codes "google.golang.org/grpc/codes"status "google.golang.org/grpc/status"protoreflect "google.golang.org/protobuf/reflect/protoreflect"protoimpl "google.golang.org/protobuf/runtime/protoimpl"reflect "reflect"sync "sync"
)const (// Verify that this generated code is sufficiently up-to-date._ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)// Verify that runtime/protoimpl is sufficiently up-to-date._ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)type RegisterMessage struct {state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFieldsId   int32  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`Info string `protobuf:"bytes,3,opt,name=info,proto3" json:"info,omitempty"`
}func (x *RegisterMessage) Reset() {*x = RegisterMessage{}if protoimpl.UnsafeEnabled {mi := &file_message_proto_msgTypes[0]ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))ms.StoreMessageInfo(mi)}
}func (x *RegisterMessage) String() string {return protoimpl.X.MessageStringOf(x)
}func (*RegisterMessage) ProtoMessage() {}func (x *RegisterMessage) ProtoReflect() protoreflect.Message {mi := &file_message_proto_msgTypes[0]if protoimpl.UnsafeEnabled && x != nil {ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))if ms.LoadMessageInfo() == nil {ms.StoreMessageInfo(mi)}return ms}return mi.MessageOf(x)
}// Deprecated: Use RegisterMessage.ProtoReflect.Descriptor instead.
func (*RegisterMessage) Descriptor() ([]byte, []int) {return file_message_proto_rawDescGZIP(), []int{0}
}func (x *RegisterMessage) GetId() int32 {if x != nil {return x.Id}return 0
}func (x *RegisterMessage) GetName() string {if x != nil {return x.Name}return ""
}func (x *RegisterMessage) GetInfo() string {if x != nil {return x.Info}return ""
}type RegisterResponse struct {state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFieldsResponse string `protobuf:"bytes,1,opt,name=response,proto3" json:"response,omitempty"`
}func (x *RegisterResponse) Reset() {*x = RegisterResponse{}if protoimpl.UnsafeEnabled {mi := &file_message_proto_msgTypes[1]ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))ms.StoreMessageInfo(mi)}
}func (x *RegisterResponse) String() string {return protoimpl.X.MessageStringOf(x)
}func (*RegisterResponse) ProtoMessage() {}func (x *RegisterResponse) ProtoReflect() protoreflect.Message {mi := &file_message_proto_msgTypes[1]if protoimpl.UnsafeEnabled && x != nil {ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))if ms.LoadMessageInfo() == nil {ms.StoreMessageInfo(mi)}return ms}return mi.MessageOf(x)
}// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead.
func (*RegisterResponse) Descriptor() ([]byte, []int) {return file_message_proto_rawDescGZIP(), []int{1}
}func (x *RegisterResponse) GetResponse() string {if x != nil {return x.Response}return ""
}var File_message_proto protoreflect.FileDescriptorvar file_message_proto_rawDesc = []byte{0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,0x49, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61,0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02,0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03,0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x2e, 0x0a, 0x10, 0x52, 0x65,0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a,0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x41, 0x0a, 0x08, 0x52, 0x65,0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x0c, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65,0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x10, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x11, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73,0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 0x5a,0x07, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}var (file_message_proto_rawDescOnce sync.Oncefile_message_proto_rawDescData = file_message_proto_rawDesc
)func file_message_proto_rawDescGZIP() []byte {file_message_proto_rawDescOnce.Do(func() {file_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_proto_rawDescData)})return file_message_proto_rawDescData
}var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_message_proto_goTypes = []interface{}{(*RegisterMessage)(nil),  // 0: RegisterMessage(*RegisterResponse)(nil), // 1: RegisterResponse
}
var file_message_proto_depIdxs = []int32{0, // 0: Register.TestRegister:input_type -> RegisterMessage1, // 1: Register.TestRegister:output_type -> RegisterResponse1, // [1:2] is the sub-list for method output_type0, // [0:1] is the sub-list for method input_type0, // [0:0] is the sub-list for extension type_name0, // [0:0] is the sub-list for extension extendee0, // [0:0] is the sub-list for field type_name
}func init() { file_message_proto_init() }
func file_message_proto_init() {if File_message_proto != nil {return}if !protoimpl.UnsafeEnabled {file_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {switch v := v.(*RegisterMessage); i {case 0:return &v.statecase 1:return &v.sizeCachecase 2:return &v.unknownFieldsdefault:return nil}}file_message_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {switch v := v.(*RegisterResponse); i {case 0:return &v.statecase 1:return &v.sizeCachecase 2:return &v.unknownFieldsdefault:return nil}}}type x struct{}out := protoimpl.TypeBuilder{File: protoimpl.DescBuilder{GoPackagePath: reflect.TypeOf(x{}).PkgPath(),RawDescriptor: file_message_proto_rawDesc,NumEnums:      0,NumMessages:   2,NumExtensions: 0,NumServices:   1,},GoTypes:           file_message_proto_goTypes,DependencyIndexes: file_message_proto_depIdxs,MessageInfos:      file_message_proto_msgTypes,}.Build()File_message_proto = out.Filefile_message_proto_rawDesc = nilfile_message_proto_goTypes = nilfile_message_proto_depIdxs = nil
}// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6// RegisterClient is the client API for Register service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type RegisterClient interface {TestRegister(ctx context.Context, in *RegisterMessage, opts ...grpc.CallOption) (*RegisterResponse, error)
}type registerClient struct {cc grpc.ClientConnInterface
}func NewRegisterClient(cc grpc.ClientConnInterface) RegisterClient {return &registerClient{cc}
}func (c *registerClient) TestRegister(ctx context.Context, in *RegisterMessage, opts ...grpc.CallOption) (*RegisterResponse, error) {out := new(RegisterResponse)err := c.cc.Invoke(ctx, "/Register/TestRegister", in, out, opts...)if err != nil {return nil, err}return out, nil
}// RegisterServer is the server API for Register service.
type RegisterServer interface {TestRegister(context.Context, *RegisterMessage) (*RegisterResponse, error)
}// UnimplementedRegisterServer can be embedded to have forward compatible implementations.
type UnimplementedRegisterServer struct {
}func (*UnimplementedRegisterServer) TestRegister(context.Context, *RegisterMessage) (*RegisterResponse, error) {return nil, status.Errorf(codes.Unimplemented, "method TestRegister not implemented")
}func RegisterRegisterServer(s *grpc.Server, srv RegisterServer) {s.RegisterService(&_Register_serviceDesc, srv)
}func _Register_TestRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {in := new(RegisterMessage)if err := dec(in); err != nil {return nil, err}if interceptor == nil {return srv.(RegisterServer).TestRegister(ctx, in)}info := &grpc.UnaryServerInfo{Server:     srv,FullMethod: "/Register/TestRegister",}handler := func(ctx context.Context, req interface{}) (interface{}, error) {return srv.(RegisterServer).TestRegister(ctx, req.(*RegisterMessage))}return interceptor(ctx, in, info, handler)
}var _Register_serviceDesc = grpc.ServiceDesc{ServiceName: "Register",HandlerType: (*RegisterServer)(nil),Methods: []grpc.MethodDesc{{MethodName: "TestRegister",Handler:    _Register_TestRegister_Handler,},},Streams:  []grpc.StreamDesc{},Metadata: "message.proto",
}

创建服务结构体

创建需要实现的服务go文件,代码如下:

package serverimport ("context""fmt""learn-grpc/proto"
)type GrpcServer struct {proto.UnimplementedRegisterServer
}func (g *GrpcServer) TestRegister(ctx context.Context, req *proto.RegisterMessage) (*proto.RegisterResponse, error) {fmt.Printf("获取消息:id=%d,name=%s,info=%s\n", req.Id, req.Name, req.Info)return &proto.RegisterResponse{Response: "接收到了"}, nil
}

对于消息的处理就是简单的打印和返回一个接收到了的消息。

服务启动代码如下:

package mainimport ("fmt""google.golang.org/grpc""learn-grpc/proto""learn-grpc/server""math""net"
)func main() {listen, err := net.Listen("tcp", ":8001")if err != nil {return}var options = []grpc.ServerOption{grpc.MaxRecvMsgSize(math.MaxInt32),grpc.MaxSendMsgSize(1073741824),}grpc_server := grpc.NewServer(options...)proto.RegisterRegisterServer(grpc_server, &server.GrpcServer{})defer func() {grpc_server.Stop()listen.Close()}()fmt.Println("start...")err = grpc_server.Serve(listen)if err != nil {return}}

启动看看

创建客户端测试

创建一个客户端进行测试。目录结构如下:

client.go代码如下:

package serverimport ("context""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""learn-grpc/proto"
)func Handle() {var serviceHost = "127.0.0.1:8001"conn, err := grpc.Dial(serviceHost, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {fmt.Println(err)}defer conn.Close()grpc_client := proto.NewRegisterClient(conn)rsp, err := grpc_client.TestRegister(context.TODO(), &proto.RegisterMessage{Id:   100,Name: "张三",Info: "写点什么好呢?",})if err != nil {fmt.Println(err)}fmt.Println(rsp)
}

client_test.go代码如下:

package serverimport "testing"func TestHandle(t *testing.T) {Handle()
}

执行一下看看结果。

OK,没什么问题。

小结

之前看了一些人的评论,说有的人文章里面就是几段代码,一句说明没有,在评选很多活动的时候应该认定该类文章属于质量不好,不应该获奖。我看完有点无奈。

不知道有多少人和我一样,其实我在看一些文章的时候或者在找一些问题解决方案的时候,我更愿意看代码。程序语言往往最真实,如果代码里面有几句注释会更好。如果我想分享一段工具代码给大家,每次都需要把涉及到的原理都写一遍,说真的我会不想写,太累了。原理性的东西官网上都有,而我也不想做个搬运工。或者有些人只是想分享一些东西而写文章,写给自己看,写给一些有一定基础的人看就好了。

所以,不要为了凑字数去写东西,有时候一段代码比千言万语有用的多。告诫我自己,提炼文字,少写废话。

Go语学习笔记 - grpc server/client protobuf | 从零开始Go语言相关推荐

  1. Go语学习笔记 - websocket gorilla(附测试代码) | 从零开始Go语言

    目录 项目结构 消息结构 服务端代码 定义客户端行为 服务启动 测试代码 总结 学习笔记,写到哪是哪. websocket也是常用的协议了,在上一篇中主要测试使用了一下grpc. 下面我会把代码贴出来 ...

  2. x%3e=y%3e=z的c语言表达式,我的C语学习笔记-C语言教程(三).doc

    我的C语学习笔记- C语言教程(三) C语言教程---第一章: C语言概论 C语言教程---第二章: 数据类型.运算符.表达式 C语言教程---第三章: C语言程序设计初步 C语言教程---第四章: ...

  3. c语言第七章函数笔记,我的C语学习笔记-C语言教程(七).doc

    我的C语学习笔记- C语言教程(七) C语言教程---第一章: C语言概论 C语言教程---第二章: 数据类型.运算符.表达式 C语言教程---第三章: C语言程序设计初步 C语言教程---第四章: ...

  4. Go语学习笔记 - gorm使用 - gorm处理错误 Web框架Gin(十)

    学习笔记,写到哪是哪. 接着上一篇文章:Go语学习笔记 - gorm使用 - 原生sql.命名参数.Rows.ToSQL | Web框架Gin(九)_的博客-CSDN博客 目前gorm对数据库的一些操 ...

  5. Go语学习笔记 - 增加时间工具 | Web框架Gin(五)

    学习笔记,写到哪是哪. 接着上一篇的文章:Go语学习笔记 - 跨域配置.全局异常捕获 | Web框架Gin(四)_剑客阿良_ALiang的博客-CSDN博客_gin全局异常捕获 在上一篇中已经将一些基 ...

  6. R语言学习笔记——入门篇:第一章-R语言介绍

    R语言 R语言学习笔记--入门篇:第一章-R语言介绍 文章目录 R语言 一.R语言简介 1.1.R语言的应用方向 1.2.R语言的特点 二.R软件的安装 2.1.Windows/Mac 2.2.Lin ...

  7. C语言程序设计学习笔记:P1-程序设计与C语言

    本系列博客用于记录学习浙江大学翁恺老师的C语言程序设计,系列笔记链接如下: C语言程序设计学习笔记:P1-程序设计与C语言 C语言程序设计学习笔记:P2-计算 C语言程序设计学习笔记:P3-判断 C语 ...

  8. 《流畅的python》学习笔记之python是什么类型的语言?

    讨论类型时,最好考虑两条不同的坐标线! 强类型和弱类型 如果一门语言很少隐式转换类型,说明它是强类型语言.如果经常这么做,说明它是弱类型语言.其中,java,c++和python是强类型语言,php, ...

  9. 冰冰学习笔记:简单了解protobuf

    欢迎各位大佬光临本文章!!! 还请各位大佬提出宝贵的意见,如发现文章错误请联系冰冰,冰冰一定会虚心接受,及时改正. 本系列文章为冰冰学习编程的学习笔记,如果对您也有帮助,还请各位大佬.帅哥.美女点点支 ...

最新文章

  1. python文件关键行数_Python计算大文件行数方法及性能比较
  2. 设计强大的云应用程序
  3. Linux下du加强版,灵活快速定位硬盘使用情况,无需安装
  4. IE8 CSS hack
  5. Safari调试iOS应用
  6. Linux环境下安装Tomcat
  7. PHP中的 fastcgi_finish_request();
  8. 在maven引入一个maven仓库中不存在的jar,安装本地底仓库
  9. Java PipedInputStream available()方法与示例
  10. Python的subprocess模块(二)
  11. 谷歌Gmail诞生记:十年回首
  12. MATLAB关于Mesh的相关命令
  13. kafka中的数据发送保障
  14. 服务端软件安全测评标准及实施指南 V1.0
  15. 文件删除如何恢复?电脑数据恢复,4个详细方法
  16. 他曾被视为马斯克第二,现在是等着坐牢的骗子
  17. 在html页头设置不缓存
  18. PowerManagerService类大致解读
  19. linux h3c 802.1客户端,OH3C 的安装及使用 H3C 802.1x Client for OpenWrt
  20. 强大的iOS开发必备工具

热门文章

  1. bootstrap模态窗口
  2. 窗体位置设置(StartPosition属性)
  3. 高薪IT行业--创新者的解答
  4. java process destory_Java Process destroy()方法
  5. 如何开通www国际域名个人网站
  6. js逆向之爬取网易云音乐和歌曲评论
  7. Windows: net和shutdown命令重启远程电脑
  8. Projected Gradient Methods for Nonnegative Matrix Factorization
  9. introduction to data science w4
  10. 联科教育携手51CTO技术直播课第四讲:Exchange 2013和Lync 2013企业整合应用