Go语学习笔记 - grpc server/client protobuf | 从零开始Go语言
目录
创建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 ®isterClient{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语言相关推荐
- Go语学习笔记 - websocket gorilla(附测试代码) | 从零开始Go语言
目录 项目结构 消息结构 服务端代码 定义客户端行为 服务启动 测试代码 总结 学习笔记,写到哪是哪. websocket也是常用的协议了,在上一篇中主要测试使用了一下grpc. 下面我会把代码贴出来 ...
- x%3e=y%3e=z的c语言表达式,我的C语学习笔记-C语言教程(三).doc
我的C语学习笔记- C语言教程(三) C语言教程---第一章: C语言概论 C语言教程---第二章: 数据类型.运算符.表达式 C语言教程---第三章: C语言程序设计初步 C语言教程---第四章: ...
- c语言第七章函数笔记,我的C语学习笔记-C语言教程(七).doc
我的C语学习笔记- C语言教程(七) C语言教程---第一章: C语言概论 C语言教程---第二章: 数据类型.运算符.表达式 C语言教程---第三章: C语言程序设计初步 C语言教程---第四章: ...
- Go语学习笔记 - gorm使用 - gorm处理错误 Web框架Gin(十)
学习笔记,写到哪是哪. 接着上一篇文章:Go语学习笔记 - gorm使用 - 原生sql.命名参数.Rows.ToSQL | Web框架Gin(九)_的博客-CSDN博客 目前gorm对数据库的一些操 ...
- Go语学习笔记 - 增加时间工具 | Web框架Gin(五)
学习笔记,写到哪是哪. 接着上一篇的文章:Go语学习笔记 - 跨域配置.全局异常捕获 | Web框架Gin(四)_剑客阿良_ALiang的博客-CSDN博客_gin全局异常捕获 在上一篇中已经将一些基 ...
- R语言学习笔记——入门篇:第一章-R语言介绍
R语言 R语言学习笔记--入门篇:第一章-R语言介绍 文章目录 R语言 一.R语言简介 1.1.R语言的应用方向 1.2.R语言的特点 二.R软件的安装 2.1.Windows/Mac 2.2.Lin ...
- C语言程序设计学习笔记:P1-程序设计与C语言
本系列博客用于记录学习浙江大学翁恺老师的C语言程序设计,系列笔记链接如下: C语言程序设计学习笔记:P1-程序设计与C语言 C语言程序设计学习笔记:P2-计算 C语言程序设计学习笔记:P3-判断 C语 ...
- 《流畅的python》学习笔记之python是什么类型的语言?
讨论类型时,最好考虑两条不同的坐标线! 强类型和弱类型 如果一门语言很少隐式转换类型,说明它是强类型语言.如果经常这么做,说明它是弱类型语言.其中,java,c++和python是强类型语言,php, ...
- 冰冰学习笔记:简单了解protobuf
欢迎各位大佬光临本文章!!! 还请各位大佬提出宝贵的意见,如发现文章错误请联系冰冰,冰冰一定会虚心接受,及时改正. 本系列文章为冰冰学习编程的学习笔记,如果对您也有帮助,还请各位大佬.帅哥.美女点点支 ...
最新文章
- python文件关键行数_Python计算大文件行数方法及性能比较
- 设计强大的云应用程序
- Linux下du加强版,灵活快速定位硬盘使用情况,无需安装
- IE8 CSS hack
- Safari调试iOS应用
- Linux环境下安装Tomcat
- PHP中的 fastcgi_finish_request();
- 在maven引入一个maven仓库中不存在的jar,安装本地底仓库
- Java PipedInputStream available()方法与示例
- Python的subprocess模块(二)
- 谷歌Gmail诞生记:十年回首
- MATLAB关于Mesh的相关命令
- kafka中的数据发送保障
- 服务端软件安全测评标准及实施指南 V1.0
- 文件删除如何恢复?电脑数据恢复,4个详细方法
- 他曾被视为马斯克第二,现在是等着坐牢的骗子
- 在html页头设置不缓存
- PowerManagerService类大致解读
- linux h3c 802.1客户端,OH3C 的安装及使用 H3C 802.1x Client for OpenWrt
- 强大的iOS开发必备工具
热门文章
- bootstrap模态窗口
- 窗体位置设置(StartPosition属性)
- 高薪IT行业--创新者的解答
- java process destory_Java Process destroy()方法
- 如何开通www国际域名个人网站
- js逆向之爬取网易云音乐和歌曲评论
- Windows: net和shutdown命令重启远程电脑
- Projected Gradient Methods for Nonnegative Matrix Factorization
- introduction to data science w4
- 联科教育携手51CTO技术直播课第四讲:Exchange 2013和Lync 2013企业整合应用