刘沙河 刘沙河
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希

花开半夏,半夏花开
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希
  • go语言基础

  • go语言进阶

    • go 泛型
    • go条件编译
    • 分布式从ACID、CAP、BASE的理论推进
    • go链接参数 ldflags
    • TCP网络连接以及TIME_WAIT的意义
    • Go异常处理
    • Go性能调优 pprof
    • Go语言设计模式
    • Go 切片的截取
    • Go runtime详解
    • go执行外部命令
    • 标准库container三剑客:head、list、ring
    • go与http代理
    • Go内存管理
    • Go垃圾回收机制
    • Go语言中的并发编程
    • Go协程调度原理及GPM模型
    • Go中逃逸现象, 变量+堆栈
    • Go面向对象的思维理解interface
    • Go中的Defer
    • Go和Python中的深浅拷贝
    • Go语言内存对齐
    • 流和IO多路复用
    • 单点Server的N种并发模型汇总
    • 控制goroutine的数量
    • 配置管理库—Viper
    • 高性能日志库zap
    • Go中的Mutex和RWMutex.md
    • sqlx的使用
    • 分布式id 库snowflake和sonyflake
    • sync.Pool 复用对象
    • sync.Once 单例模式
    • sync.Cond 条件变量
    • unsafe.Pointer 和 uintptr
    • go 信号量
    • go语言代码优化技巧
    • go 接口型函数
    • 位运算
    • cgo教程
    • go调用lib和so动态库
      • go 调用dll
        • 1. sysCall.LoadDll(推荐使用)
        • 2. Cgo调用
        • 3. 动态调用 dll (推荐使用)
      • go 调用so
        • 1. Cgo调用
        • 2. 动态调用 so(推荐使用)
      • 大坑!!!
  • go语言实现原理

  • gin框架

  • gorm

  • go测试

  • Go语言
  • go语言进阶
bigox
2023-08-22
目录

go调用lib和so动态库

# go 调用dll

# 1. sysCall.LoadDll(推荐使用)

  • 系统调用是程序向操作系统内核请求服务的过程,通常包含硬件相关的服务(例如访问硬盘),创建新进程等。系统调用提供了一个进程和操作系统之间的接口

  • fmt中的syscall

    func Println(a ...interface{}) (n int, err error) {
        return Fprintln(os.Stdout, a...)
    }
    
    Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
    
    1
    2
    3
    4
    5
  • 调用dll 示例

    dll, err := syscall.LoadDLL("scan.dll")
    //根据名称从dll中查找proc
    MemoryStream_Get = dll.FindProc("AllocateMemory")
    MemoryStream_Get.Call()
    
    1
    2
    3
    4
  • 此方式可以 也可以调用go 代码打包的dll

# 2. Cgo调用

  • 项目目录结构如下

    ├── include
    │     └── add.c
    │     └── add.h
    ├── lib
    │     └── libadd.dll
    └── main.go
    
    1
    2
    3
    4
    5
    6
  • add.h

    #ifndef __ADD_H__
    #define __ADD_H__
     
    char* Add(char* src, int n);
     
    #endif
    
    
    1
    2
    3
    4
    5
    6
    7
  • add.c

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
     
    char* Add(char* src, int n)
    {
        char str[20];
        sprintf(str, "%d", n);
        char *result = malloc(strlen(src)+strlen(str)+1);
        strcpy(result, src);
        strcat(result, str);
        return result;
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • main.go

    func GetFinalStrategyString(request string) {
    
    	dll, err := syscall.LoadDLL("./middleware_c.dll")
    	if err != nil {
    		log.Fatal("Error loading DLL:", err)
    	}
    	defer dll.Release()
    
    	getFinalStrategyString, err := dll.FindProc("GetFinalStrategyString")
    	if err != nil {
    		log.Fatal("Error finding GetFinalStrategyString:", err)
    	}
    
    	freeFinalStrategyString, err := dll.FindProc("FreeFinalStrategyString")
    	if err != nil {
    		log.Fatal("Error finding FreeFinalStrategyString:", err)
    	}
    
    	// cRequest, err := syscall.UTF16PtrFromString(request)
    	// if err != nil {
    	// 	log.Fatal("Error converting request:", err)
    	// }
    
    	var cResponse *uint16
    	var responseLen uint32
    
    	ret, _, _ := getFinalStrategyString.Call(
    		uintptr(unsafe.Pointer(request)),
    		uintptr(len(request)),
    		uintptr(unsafe.Pointer(&cResponse)),
    		uintptr(unsafe.Pointer(&responseLen)),
    	)
    
    	if ret != 0 {
    		log.Fatal("ret Error:", ret)
    	}
    	fmt.Println("responseLen:", responseLen)
    	fmt.Println("cResponse:", cResponse)
    
    	cResponseBytes := (*[1 << 20]byte)(unsafe.Pointer(cResponse))[:responseLen]
    	fmt.Println("cResponseBytes:", cResponseBytes)
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43

# 3. 动态调用 dll (推荐使用)

  • 动态调用步骤

    1. 通过文件路径加载c/c++ 动态库中的 handle
    2. 在go代码中定义和c/c++ 动态库中对应的go func
    3. 使用库purego(底层是dlopen)或者sys/windows 将handle中对应的方法符号(Symbol)映射到 go func 地址上
    4. 逻辑调用
  • main.go

    import "C"
    import (
    	"context"
    	"fmt"
    	"github.com/ebitengine/purego"
    	"sync"
    )
    
    
    var (
    	getFinalStrategyString func(*C.char, C.uint, **C.char, *C.uint) C.int  //2. 定义和c/c++ 动态库中对应的go func
    	freeFinalStrategyString func(*C.char)  // 2. 定义和c/c++ 动态库中对应的go func
    	mcRunModeOnce sync.Once
    	mcRunMode     int
    )
    
    func main(){
        InitMC(libFilePath)
    }
    
    func InitMC(libFilePath string) (err error) {
    	defer func() {
    		if _err := recover(); _err != nil {
    			logger.Errorf("RegisterLibFunc panic error: %v", err)
    			err = fmt.Errorf("RegisterLibFunc panic error: %v", err.Error())
    		}
    	}()
    	...
    	mcHandle, err := LoadHandle(libFilePath)  // 1. 通过路径加载c/c++ 动态库handle
    	if err != nil {
    		logger.Errorf("LoadHandle error:%v", err.Error())
    		return err
    	}
        // 找不到函数会panic
    	purego.RegisterLibFunc(&getFinalStrategyString, mcHandle, "GetFinalStrategyString") // 3. 使用库purego将handle中对应的方法映射到go func
    	purego.RegisterLibFunc(&freeFinalStrategyString, mcHandle, "FreeFinalStrategyString")  // 3. 使用库purego将handle中对应的方法映射到go func
    	return nil
    }
    
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
  • load_linux.go

    //go:build !windows
    // +build !windows
    
    package main
    
    import "github.com/ebitengine/purego"
    
    const MCLibPath = "c.so"
    
    func LoadHandle(libPath string) (uintptr, error) {
    	return purego.Dlopen(libPath, purego.RTLD_NOW|purego.RTLD_GLOBAL)
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  • load_windows.go

    //go:build windows
    // +build windows
    
    package main
    
    import "golang.org/x/sys/windows"
    
    const MCLibPath = ""
    
    func LoadHandle(libPath string) (uintptr, error) {
    	handle, err := windows.LoadLibrary(libPath)
    	return uintptr(handle), err
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • 业务调用

    c++ 头文件

    #ifdef __cplusplus extern "C" { #endif

    MIDDLEWARE_C_EXPORT int GetFinalStrategyString( /::browserconsoleapiv3::middle_ware::GetUserStrategiesRequest request/ const char* request, unsigned request_len, /::browserconsoleapiv3::api::user::FinalGroupStrategy response/ char** response, unsigned* response_len);

    MIDDLEWARE_C_EXPORT void FreeFinalStrategyString(const char*);

    #ifdef __cplusplus } #endif

    package middleware
    
    /*
    #include <stdlib.h>  // 要引入
    */
    import "C"
    import (
    	"fmt"
    	"unsafe"
    )
    
    type MiddlewareC struct {
    	response *C.char
    }
    
    func (mc *MiddlewareC) GetFinalStrategyString(req string) (resByte []byte, err error) {
    	cRequest := C.CString(req)
    	defer C.free(unsafe.Pointer(cRequest))
    	var (
    		reqLen      C.uint
    		cResponse   *C.char
    		responseLen C.uint
    		resCodeC    C.int
    	)
    	reqLen = C.uint(len(req))
    	resCodeC = getFinalStrategyString(cRequest, reqLen, &cResponse, &responseLen)  //4. 真正的业务调用
    	resCode := int(resCodeC)
    	if resCode != 0 {
    		errMsg, ok := MCError[resCode]
    		if !ok {
    			err = fmt.Errorf(
    				"unknown error code, code:%v, cResponse: %v, cResponse len: %v",
    				resCode, cResponse, responseLen,
    			)
    		} else {
    			err = fmt.Errorf(
    				"middleware error msg: %v, error code: %v, cResponse: %v, cResponse len: %v",
    				errMsg, resCode, cResponse, responseLen,
    			)
    		}
    		return resByte, err
    	}
    	resByte = C.GoBytes(unsafe.Pointer(cResponse), C.int(responseLen))
    	mc.response = cResponse
    	return resByte, nil
    }
    
    func (mc *MiddlewareC) MustFreeFinalStrategyString() {
    	freeFinalStrategyString(mc.response)
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51

# go 调用so

# 1. Cgo调用

  • 项目目录结构如下

    ├── include
    │     └── add.c
    │     └── add.h
    ├── lib
    │     └── libadd.so
    └── main.go
    
    1
    2
    3
    4
    5
    6
  • add.h

    #ifndef __ADD_H__
    #define __ADD_H__
     
    char* Add(char* src, int n);
     
    #endif
    
    
    1
    2
    3
    4
    5
    6
    7
  • add.c

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
     
    char* Add(char* src, int n)
    {
        char str[20];
        sprintf(str, "%d", n);
        char *result = malloc(strlen(src)+strlen(str)+1);
        strcpy(result, src);
        strcat(result, str);
        return result;
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • linux 下编译

    会在当前目录下生成 libadd.so 文件, 在 Linux 下可用 nm -D libadd.so 查看其中的方法

    gcc -fPIC -shared -o lib/libadd.so include/add.c
    
    1
  • main.go

    package main
    
    /*
    // 头文件的位置,相对于源文件是当前目录,所以是 .,头文件在多个目录时写多个  #cgo CFLAGS: ...
    #cgo CFLAGS: -I./include
    // 从哪里加载动态库,位置与文件名,-ladd 加载 libadd.so 文件
    #cgo LDFLAGS: -L./lib -ladd -Wl,-rpath,lib
    #include "add.h"
    */
    import "C"
    import "fmt"
     
    func main() {
      val := C.Add(C.CString("go"), 2023)
      fmt.Println("run c: ", C.GoString(val))
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
  • 注意:

    • 如果把#cgo LDFLAGS: -L./lib -ladd -Wl,-rpath,lib 改为 cgo LDFLAGS: -L./lib -ladd编译不会报错,执行时会出错

      error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
      
      1
    • 设置了环境变量 LD_LIBRARY_PATH=/home/.../lib 也能让它跑起来

      LD_LIBRARY_PATH=lib/ ./demo
      
      1

# 2. 动态调用 so(推荐使用)

  • 动态调用步骤

    1. 通过路径加载c/c++ 动态库 handle
    2. 定义和c/c++ 动态库中对应的go func
    3. 使用库purego 将handle中对应的方法映射到go func
    4. 逻辑调用
  • main.go

    import "C"
    import (
    	"context"
    	"fmt"
    	"github.com/ebitengine/purego"
    	"sync"
    )
    
    
    var (
    	getFinalStrategyString func(*C.char, C.uint, **C.char, *C.uint) C.int  //2. 定义和c/c++ 动态库中对应的go func
    	freeFinalStrategyString func(*C.char)  // 2. 定义和c/c++ 动态库中对应的go func
    	mcRunModeOnce sync.Once
    	mcRunMode     int
    )
    
    func main(){
        InitMC(libFilePath)
    }
    
    func InitMC(libFilePath string) (err error) {
    	defer func() {
    		if _err := recover(); _err != nil {
    			logger.Errorf("RegisterLibFunc panic error: %v", err)
    			err = fmt.Errorf("RegisterLibFunc panic error: %v", err.Error())
    		}
    	}()
    	...
    	mcHandle, err := LoadHandle(libFilePath)  // 1. 通过路径加载c/c++ 动态库handle
    	if err != nil {
    		logger.Errorf("LoadHandle error:%v", err.Error())
    		return err
    	}
        // 找不到函数会panic
    	purego.RegisterLibFunc(&getFinalStrategyString, mcHandle, "GetFinalStrategyString") // 3. 使用库purego将handle中对应的方法映射到go func
    	purego.RegisterLibFunc(&freeFinalStrategyString, mcHandle, "FreeFinalStrategyString")  // 3. 使用库purego将handle中对应的方法映射到go func
    	return nil
    }
    
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
  • load_linux.go

    //go:build !windows
    // +build !windows
    
    package main
    
    import "github.com/ebitengine/purego"
    
    const MCLibPath = "c.so"
    
    func LoadHandle(libPath string) (uintptr, error) {
    	return purego.Dlopen(libPath, purego.RTLD_NOW|purego.RTLD_GLOBAL)
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  • load_windows.go

    //go:build windows
    // +build windows
    
    package main
    
    import "golang.org/x/sys/windows"
    
    const MCLibPath = ""
    
    func LoadHandle(libPath string) (uintptr, error) {
    	handle, err := windows.LoadLibrary(libPath)
    	return uintptr(handle), err
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • 业务调用

    c++ 头文件

    #ifdef __cplusplus extern "C" { #endif

    MIDDLEWARE_C_EXPORT int GetFinalStrategyString( /::browserconsoleapiv3::middle_ware::GetUserStrategiesRequest request/ const char* request, unsigned request_len, /::browserconsoleapiv3::api::user::FinalGroupStrategy response/ char** response, unsigned* response_len);

    MIDDLEWARE_C_EXPORT void FreeFinalStrategyString(const char*);

    #ifdef __cplusplus } #endif

    package middleware
    
    /*
    #include <stdlib.h>  // 要引入
    */
    import "C"
    import (
    	"fmt"
    	"unsafe"
    )
    
    type MiddlewareC struct {
    	response *C.char
    }
    
    func (mc *MiddlewareC) GetFinalStrategyString(req string) (resByte []byte, err error) {
    	cRequest := C.CString(req)
    	defer C.free(unsafe.Pointer(cRequest))
    	var (
    		reqLen      C.uint
    		cResponse   *C.char
    		responseLen C.uint
    		resCodeC    C.int
    	)
    	reqLen = C.uint(len(req))
    	resCodeC = getFinalStrategyString(cRequest, reqLen, &cResponse, &responseLen)  //4. 真正的业务调用
    	resCode := int(resCodeC)
    	if resCode != 0 {
    		errMsg, ok := MCError[resCode]
    		if !ok {
    			err = fmt.Errorf(
    				"unknown error code, code:%v, cResponse: %v, cResponse len: %v",
    				resCode, cResponse, responseLen,
    			)
    		} else {
    			err = fmt.Errorf(
    				"middleware error msg: %v, error code: %v, cResponse: %v, cResponse len: %v",
    				errMsg, resCode, cResponse, responseLen,
    			)
    		}
    		return resByte, err
    	}
    	resByte = C.GoBytes(unsafe.Pointer(cResponse), C.int(responseLen))
    	mc.response = cResponse
    	return resByte, nil
    }
    
    func (mc *MiddlewareC) MustFreeFinalStrategyString() {
    	freeFinalStrategyString(mc.response)
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51

# 大坑!!!

  • 动态库中的崩溃会直接导致主程序崩溃!!!!!!!!!!

  • 崩溃测试

    • 创建崩溃程序

      package main
      
      import "C"
      import "fmt"
      
      //export PrintTest
      func PrintTest() int {
      	defer func() {
      		if err := recover(); err != nil {
      			print("err\n")
      			print(err)
      		}
      	}()
      	print("hello world\n")
      	var a []int
      	a[0] = 1
      	print("hello world 2\n")
      	return 1
      }
      
      func main() {
      	fmt.Println("call cpp test")
      }
      
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
    • 打包dll文件go build -o pt.dll -buildmode=c-shared main.go

    • 主程序调用

      package main
      
      import "C"
      import (
      	"github.com/ebitengine/purego"
      	win "golang.org/x/sys/windows"
      	"log"
      )
      
      var PrintTest func() int
      
      func openLibrary(name string) (uintptr, error) {
      	handle, err := win.LoadLibrary(name)
      	return uintptr(handle), err
      }
      
      func main() {
          // recover无效了!
      	defer func() {
      		if err := recover(); err != nil {
      			log.Println("err")
      			log.Println(err)
      		}
      	}()
      
      	lib, err := openLibrary("./dll/pt.dll")
      	if err != nil {
      		log.Fatalln(err)
      	}
      	purego.RegisterLibFunc(&PrintTest, lib, "PrintTest")
      	res := PrintTest()
      	log.Println(res)
      }
      
      // !!! 直接panic,recover无效
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
#Go
上次更新: 2023/09/01, 22:31:42
cgo教程
channel 实现原理

← cgo教程 channel 实现原理→

最近更新
01
go与http代理
05-24
02
自制申威架构k8s-reloader
12-06
03
Docker Buildx 教程
12-01
更多文章>
Theme by Vdoing | Copyright © 2020-2024 小刘扎扎 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式