• go proto 简单学习


    环境安装:

    参考链接: go中使用protobuf

    protoc 编译遇到问题

    编译问题

    $ protoc --go_out=./ *.proto
    protoc-gen-go: unable to determine Go import path for "test.proto"
    
    Please specify either:
            • a "go_package" option in the .proto source file, or
            • a "M" argument on the command line.
    
    See https://developers.google.com/protocol-buffers/docs/reference/go-generated#package for more information.
    
    --go_out: protoc-gen-go: Plugin failed with status code 1.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    解决办法

    指定包名的位置改成:
    option go_package = "./";
    重新执行
    protoc --go_out=./ *.proto
    即可
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Proto消息获取

    关于通过proto消息名,创建proto.Message对象
    关于protov1 v2版本的区别,v2版本的动态特性更强

    proto v1版本实现代码。
    //该实现仅用于proto v1版本实现 即	github.com/golang/protobuf 库
    func parseRequest(msgName protoreflect.FullName, data []byte) (proto.Message,error) {
    	// 获取full name对应的message ,如果不存在则返回error
    	msgType, err := protoregistry.GlobalTypes.FindMessageByName(msgName)
    	if err != nil {
    		return nil, err
    	}
    	//上面返回的是一个message 反射类型,需要把它new出一个 protoreflect.Message类型然后转换成protoiface.MessageV1
    	//此时 根据源代码显示 proto.Message实现为 type Message = protoiface.MessageV1
    	//即type Message 为 protoiface.MessageV1 的别名
    	msg := proto.MessageV1(msgType.New())
    	err = proto.Unmarshal(data, msg)
    	if err != nil {
    		return nil, err
    	}
    	return msg, nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    proto v2版本实现如下
    //该实现仅用于proto v2版本实现 即"google.golang.org/protobuf/proto"库
    func parseRequest(msgName protoreflect.FullName, data []byte) (proto.Message,error) {
    	// 获取full name对应的message ,如果不存在则返回error
    	msgType, err := protoregistry.GlobalTypes.FindMessageByName(msgName)
    	if err != nil {
    		return nil, err
    	}
    	//上面返回的是一个message type 反射类型,需要把它new出一个 protoreflect.Message类型然后转换成protoreflect.ProtoMessage
    	//此时 根据源代码显示 proto.Message实现为 type Message = protoreflect.ProtoMessage	
    	//即type Message 为 protoreflect.ProtoMessage的别名
    	msg := msgType.New().Interface()
    	err = proto.Unmarshal(data, msg)
    	if err != nil {
    		return nil, err
    	}
    	return msg, nil
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    动态链接库编译

    32位

    set CGO_ENABLED=1
    set GOOS=windows
    set GOARCH=386
    go build -buildmode=c-shared  -ldflags "-s -w" -o "pb32.dll"
    
    • 1
    • 2
    • 3
    • 4

    64位

    set CGO_ENABLED=1
    set GOOS=windows
    set GOARCH=amd64
    go build -buildmode=c-shared  -ldflags "-s -w" -o "pb64.dll"
    
    • 1
    • 2
    • 3
    • 4

    代码细节

    一、必要准备
    • 必须导入 import "C" 并且要单独一行,在其上方的注释中必须写上 #include
    • 这是在导入 C 的标准动态库头文件,若不导入将有几率编译失败。
    二、形参与返回值
    • 在go中,除了 string 特殊外,其他intbool,等基本类型原本怎样还是怎样;
    • string 与返回值 string 都改成 *C.char 类型,其他基本类型不用改;
    • 有三个方法比较重要,C.CString 转成c字符串,C.GoString 转成go字符串 , C.free 释放内存;
    • 只要用到 C.CString 此方法,就必须记得释放内存。
    三、内存泄漏
    • 如果使用了 C.CString 却不使用 C.free ,内存占用只会越来越大,最后奔溃;
    • 释放内存时,请不要重复取地址,例如 unsafe.Pointer(&xx变量) ,这样等于没释放;
    • 也可能是 vc6 的原因,使用 defer 在即将出栈时释放,会造成调用得不到返回值;
    • 解决方法,返回c字符串的同时,也将需要释放的指针传出去,再定义一个释放函数例如 Free() 用于释放!
    四、如何编译
    • 安装 tdm-gcc 编译器,可选择64位,依然可以编译出32位,下载地址:https://jmeubank.github.io/tdm-gcc/download/
    • 若想彻底解决 gcc 兼容性问题建议下载 msys2 后再安装 gcc,此条为建议并不一定需要;

    GoLand

    XX链接

    所有资料来源于互联网 感谢各位前辈~

  • 相关阅读:
    并网逆变器学习笔记3---三电平拓扑和中点电位平衡
    设计模式-桥接模式
    680. 验证回文串 II-先删后验
    Observability:使用 OpenTelemetry 手动检测 Go 应用程序
    自定义redission装配和集成分布式开源限流业务组件ratelimiter-spring-boot-starter的正确姿势
    当我问chatGPT怎么拟合曲线
    腾讯云重新注册算不算新用户?算!
    modelsim波形高度异常,值为X
    java基础巩固14
    最长算术(暑假每日一题 11)
  • 原文地址:https://blog.csdn.net/u014431237/article/details/126563199