用Lua或c调用go的库

news2024/12/23 1:30:30

用Lua或c调用go编写的库或函数

  • 背景
  • 思路
  • 操作
    • go
    • lua
    • 代码汇总
  • 参考文章

又好久没有更新了,这次肯定又是遇上了什么问题,但又解决了的,才跑过来更新的。我也是翻遍了全网都没找到lua去调go代码的,于是干脆自己写一个

背景

作为提供统一接口的一方,由于历史原因我们是基于openresty+lua开发的。本身我们服务对上游数据要求都是明文的,一直以来都是如此。
可就有一方上游,非要传密文。因为合规原因,端上只能拿到加密数据不可避免。
但是,加密是你后端来的,那解密也过一下你后端,你后端解密透传给我明文不就好了吗?这样你想控制解密哪个字段就解密哪个字段,以后你每个端或增或减,我都不关心,专心做我的引擎不好吗??

什么?不行?上升一级去聊还是要我们做?行吧,那给SDK吧。
什么?只有go和php的?让我自己实现?拒绝🙅🏻‍♀️!实在不行你提供接口吧。
什么?没有接口,不同意支持?这日子需求 没法做了!!!

思路

不做是不可能不做的,这辈子老板都不会让我不做的。
在这里插入图片描述
老板说,只能我想办法自己做了。要么你用lua再实现一遍,要么你用别的方法。我他喵的我怎么用lua实现,go的库都是有引用第三方库的,我lua怎么找到对应的第三方库,我难道把第三方库也自己实现一遍??

这时候一个同事抛出来一个方案:当我们把go编译成一个动态链接库(.so),这样c/cpp就可以引用这个库;另外lua可以无缝引入c/cpp。那么我们可以把go编译成一个动态链接库,然后让lua去调用这个动态链接库,那不就可以做到了吗。网上有写c/cpp调用go的,但是对我而言还少一步lua。

下面讲一些操作,原理我就不讲了

操作

go

首先,起一个go项目,如果有外部库引入,建议用go mod

go mod init

创建一个go文件,并且一定要是main包的,并在其中引入C包,这个包并不真实存在,也不会被Go的compile组件见到,它会在编译前被CGO工具捕捉到,并做一些代码的改写和桩文件的生成。

package main

// #include <stdlib.h>
import "C"

里面封装好你想实现的函数,输入和输出如果是要给lua用的,那么请求用C包下的类型输出,go的string对应*C.char,其他类型可以自己找找。

注:函数名的上一行一定要写“//export Func”,否则一会链接时会找不到接口,他表示输出这个函数(别问我怎么知道的,我在这个上面被坑了半小时)

//export Func
func Func(s *C.char) *C.char {
	…………
	return C.CString(goString)
}

因为c/cpp是没有垃圾回收的,所以最好加一个Free函数去手动释放结果的内存,不然久而久之会内存泄漏。同样Free函数也是需要export的

//export Free
func Free(p unsafe.Pointer) {
	C.free(p)
}

然后写一个空的main函数,这个也是必须的。

func main() {}

接下来,让我们执行命令

go build -o 你的so.so -buildmode=c-shared 你的go文件.go

就会生成对应的.h头文件,这个你不用管。还会生成一个.so的动态链接库,这个是我们要用的,可以拷贝下来

lua

将刚刚生成的so拷贝在lua的项目目录里,让你的lua能找到就行
lua想要引用动态链接库,需要ffi包,openresty自带这个包,luajit好像也是。

local ffi = require("ffi")

然后我们定义这个go所export的函数。
注:c中是没有string的,所以形参和返回想用string的需要用char*代替

ffi.cdef [[
    char* Func1(const char* s);
    char* Func2(const char* s);
    void Free(void* p);
]]

让ffi加载我们的动态链接库

local libconvert = ffi.load("你的so.so")

将go的函数在lua中封装一次,其中调用go的函数并返回后,要将返回值再赋值给一个其他变量,因为原来的返回值我们需要去free掉

local function func1(str)
    if str == "" or str == nil then
        return str
    end

    local tmp = so.Func1(str)
    local a = ffi.string(tmp)--返回的是char*,想变成lua中string的话,需要ffi转一下
    libconvert.Free(tmp)    --释放c内存
    
    return a
end

代码汇总

local ffi = require("ffi")

ffi.cdef [[
    char* Func1(const char* s);
    char* Func2(const char* s);
    void Free(void* p);
]]

local libconvert = ffi.load(".so")

local function func1(str)
    if str == "" or str == nil then
        return str
    end

    local tmp = so.Func1(str)
    local a = ffi.string(tmp)
    libconvert.Free(tmp)    --释放c内存

    return a
end

local codec = {
    func1 = func1,
}
return codec
package main

// #include <stdlib.h>
import "C"

import (
	"******/utils"
	"strconv"
	"unsafe"
)

//编译命令:go build -o 你的so.so -buildmode=c-shared 你的go.go

//export Func1
func Func1(s *C.char) *C.char {
	//fmt.Printf("input uid:%s\n", C.GoString(s))
	n, _ := strconv.Atoi(C.GoString(s))
	e, _ := utils.Encode(n)
	return C.CString(e)
}

//export Func2
func Func2(s *C.char) *C.char {
	d, _ := utils.Decode(C.GoString(s))
	//fmt.Printf("uid.so decode uid:%v\n", uid)
	ds := strconv.Itoa(d)
	//fmt.Printf("itoa :%s\n", uidStr)
	return C.CString(ds)
}

//export Free
func Free(p unsafe.Pointer) {
	C.free(p)
}

func main() {}

好了到此,功能上的问题就解决了。我们测试了一下,是可以实现实现的。但是性能呢?这个so我看了下,没几行go代码却有12M这么大。

经过我们压测后发现,相同输入,不加这个功能和加这个功能,单pod减少了400qps。我认为是不小的损耗了,唉就是说为啥要来我这里做呢?有懂的小伙伴可以评论区交流一下。

如果你觉得这篇博客对你有帮助,那就还请给我一个大大的赞👍🏻吧。

参考文章

C/C++代码中调用golang的接口
通过 C 代码调用 Go
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/560515.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

堆结构与堆排序

二叉树的概念 满二叉树&#xff1a;二叉树的每一层的节点数都达到最大值 完全二叉树&#xff1a;满二叉树或是从左往右依次变满的树 二叉树的数组表示 01234567 堆结构&#xff08;优先级队列结构&#xff09; 完全二叉树 大根堆&#xff1…

图数据库评估难?一篇教你搞定图数据库产品评估

随着数字经济时代全面开启&#xff0c;数据作为重要的生产要素&#xff0c;赋能作用日渐凸显&#xff0c;企业逐渐开始关注自身数字化水平和数据资产价值。而当各企业数智水平提升&#xff0c;其业务环境和计算场景呈现数据间关系交错复杂的特点。在面对需要深度挖掘数据间复杂…

C语言——存储类型

目录 1. auto 自动型2. static 静态2.1 修饰变量要知道&#x1f447;&#xff08;数据在Linux内核中的分配图&#xff09; 2.2 static 的特点⭐⭐⭐⭐⭐&#xff1a;2.2 修饰函数 3. extern4. register 寄存器类型 存储类型 存储类型有&#xff1a;auto static extern register…

2023最全selenium面试题及答案,测试员没有碰到算我输.....

一、前言 Selenium&#xff0c;是一个开源的框架&#xff0c;主要用于做HTML页面的UI自动化测试。不过&#xff0c;selenium IDE在去年官方已宣告放弃维护了。官网上放着一句话&#xff0c;selenium IDE is Dead。Selenium IDE是火狐浏览器的一个插件&#xff0c;是Selenium的…

上午面了个腾讯拿 38K 出来的,让我见识到了基础的天花板

今年的校招基本已经进入大规模的开奖季了&#xff0c;很多小伙伴收获不错&#xff0c;拿到了心仪的 offer。 各大论坛和社区里也看见不少小伙伴慷慨地分享了常见的面试题和八股文&#xff0c;为此咱这里也统一做一次大整理和大归类&#xff0c;这也算是划重点了。 俗话说得好…

低功耗IC后端培训 | 盘点Power Switch Cell在实际项目中应用注意事项

下面直接进入今天的技术干货分享——全面盘点power gating cell在数字IC后端实现中的各种注意事项。 什么是Power Gating? 随着工艺制程越做越小和芯片规模越来越大&#xff0c;芯片的leakage的比重越来越高&#xff0c;数字后端实现时就得考虑leakage的优化。而leakage优化…

交通标志识别系统-卷积神经网络

介绍 使用Python作为主要开发语言&#xff0c;基于深度学习TensorFlow框架&#xff0c;搭建卷积神经网络算法。并通过对数据集进行训练&#xff0c;最后得到一个识别精度较高的模型。并基于Django框架&#xff0c;开发网页端操作平台&#xff0c;实现用户上传一张图片识别其名…

Linux 软件包管理工具

rpm命令管理软件包 1.学会看rpm包&#xff0c;通过rpm包的名字来了解这个软件包的一些基础信息xfsprogs-4.19.0-2.el8.x86_64.rpm xfsprogs 软件名字 4.19.0 版本号 2 发行次数 el8 适用于哪个操作系统&#xff08;rel8&#xff09; x86_64 软…

Streamlit应用程序使用Streamlit-Authenticator进行用户的安全身份验证实践(解决升级问题)

在Streamlit官方文档中&#xff0c;没有提供提供安全身份验证组件。目前&#xff0c;第三方streamlit-authenticator提供此功能&#xff0c;详见引用我原来的博文&#xff0c;在《Streamlit应用程序使用Streamlit-Authenticator进行用户的安全身份验证实践》文中&#xff0c;原…

Vue计算属性

1&#xff0c;为什么Vue会设计计算属性(computed property)&#xff1f; 答&#xff1a;一定程度上&#xff0c;Vue的作用就是管理呈现到HTML页面上的所有数据data的&#xff0c;每当一个data发生变化&#xff0c;Vue实例就会自动的去更新模板里面使用到data的地方&#xff0c;…

pytorch完整模型训练套路

文章目录 CIFAR10数据集简介训练模型套路1、准备数据集2、加载数据集3、搭建神经网络4、创建网络模型、定义损失函数、优化器5、训练网络6、测试数据集7、添加tensorboard8、转化为正确率9、保存模型 完整代码 本文以 CIFAR10数据集为例&#xff0c;介绍一个完整的模型训练套路…

机器学习-线性代数-向量、基底及向量空间

概述 文章目录 概述向量理解向量运算 基底与向量的坐标表示基底与向量的深入基底与向量选取与表示基底的特殊性张成空间 向量 理解 直观理解 行向量&#xff1a;把数字排成一行A [ 4 5 ] [4~ 5] [4 5]列向量&#xff1a;把数字排成一列A [ 4 5 ] \ \left [ \begin{matrix}…

多线性开发实例分享

一. 概述 首先&#xff0c;在这里有必要和大家复现一下我使用该技术的背景&#xff1a; 在使用若依框架的时候&#xff0c;由于实际开发的需要&#xff0c;我需要配置四个数据源&#xff0c;并且通过mapper轮流去查每个库的指定用户数据&#xff0c;从而去判断改库是否存在目标…

构建一个简易数据库-用C语言从头写一个sqlite的克隆 0.前言

英文源地址 一个数据库是如何工作的? 数据是以什么格式存储的(在内存以及在磁盘)?何时从内存中转移到此磁盘上?为什么每张表只能有一个主键?回滚一个事务是如何工作的?索引是以什么格式组织的?什么时候会发生全表扫描, 以及它是如何进行的?准备好的语句是以什么格式保…

#C2#S2.2~S2.3# 加入 factory/objection/virtual interface 机制

2.2 加入factory 机制 factory机制的实现被集成在了一个宏中&#xff1a;uvm_component_utils。这个宏所做的事情非常多&#xff0c;其中之一就是将my_driver登记在 UVM内部的一张表中&#xff0c;这张表是factory功能实现的基础。只要在定义一个新的类时使用这个宏&#xff0…

斐波那契数列相关简化4

看这篇文章前需要看下前面三篇文章&#xff0c;最起码第一第二篇是需要看一下的 斐波那契数列数列相关简化1_鱼跃鹰飞的博客-CSDN博客 斐波那契数列数列相关简化2_鱼跃鹰飞的博客-CSDN博客 算法玩的就是套路&#xff0c;练练就熟悉了 再来一个&#xff1a; 用1*2的瓷砖&am…

如何在 CentOS Linux 上安装和配置 DRBD?实现高可用性和数据冗余

DRBD&#xff08;Distributed Replicated Block Device&#xff09;是一种用于实现高可用性和数据冗余的开源技术。它允许在不同的服务器之间实时同步数据&#xff0c;以提供数据的冗余和容错能力。本文将详细介绍如何在 CentOS Linux 上安装和配置 DRBD。 1. 确认系统要求 在…

一文带你了解MySQL之InnoDB统计数据是如何收集的

前言 本文章收录在MySQL性能优化原理实战专栏&#xff0c;点击此处查看更多优质内容。 我们前边唠叨查询成本的时候经常用到一些统计数据&#xff0c;比如通过show table status可以看到关于表的统计数据&#xff0c;通过show index可以看到关于索引的统计数据&#xff0c;那…

MySQL之事务初步

0. 数据源 /*Navicat Premium Data TransferSource Server : localhost_3306Source Server Type : MySQLSource Server Version : 80016Source Host : localhost:3306Source Schema : tempdbTarget Server Type : MySQLTarget Server Version…

在线OJ常用输入规则

一、字符串输入规则 1.1 单行无空格字符串输入 输入连续字符串&#xff0c;cin默认空格/换行符为分割标志。 string s; //输入连续字符串&#xff0c;cin默认空格/换行符为分割标志。 cin >> s; 1.2 单行有空格字符串输入 getline函数接受带有空格的输入流&#xff…