惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
量子位
M
MIT News - Artificial intelligence
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Google DeepMind News
Google DeepMind News
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
雷峰网
雷峰网
I
InfoQ
罗磊的独立博客
博客园 - 聂微东
酷 壳 – CoolShell
酷 壳 – CoolShell
大猫的无限游戏
大猫的无限游戏
D
Docker
H
Hackread – Cybersecurity News, Data Breaches, AI and More
腾讯CDC
博客园 - 三生石上(FineUI控件)
The GitHub Blog
The GitHub Blog
K
Kaspersky official blog
P
Privacy & Cybersecurity Law Blog
S
SegmentFault 最新的问题
T
Threat Research - Cisco Blogs
H
Help Net Security
小众软件
小众软件
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
CERT Recently Published Vulnerability Notes
WordPress大学
WordPress大学
T
Tenable Blog
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - Franky
A
Arctic Wolf
T
Threatpost
Scott Helme
Scott Helme
C
Cybersecurity and Infrastructure Security Agency CISA
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
The Exploit Database - CXSecurity.com
G
GRAHAM CLULEY
Security Latest
Security Latest
Spread Privacy
Spread Privacy
L
LINUX DO - 热门话题
V
Vulnerabilities – Threatpost
P
Privacy International News Feed
S
Schneier on Security
Latest news
Latest news
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com

HaoKunT的博客

如何用 ollama 快速下载 deepseek 模型 - HaoKunT的博客 python使用gdal - HaoKunT的博客 Word中写LaTeX公式 - HaoKunT的博客 g++中的rpath和runpath - HaoKunT的博客 Ext4文件系统 - HaoKunT的博客 文件系统介绍 - HaoKunT的博客 理解shell - HaoKunT的博客 Hyper V安装ENVI - HaoKunT的博客 华为软件实习生笔试 - HaoKunT的博客 用C++实现一个命令行进度条 - HaoKunT的博客 PCA与GWPCA - HaoKunT的博客 字节后台实习生笔试题目 - HaoKunT的博客 Web终端仿真器 - HaoKunT的博客 阿里云API网关与函数计算的基础理解 - HaoKunT的博客 函数计算搭建DNS服务器 - HaoKunT的博客 DNS解析过程 - HaoKunT的博客 Github图片加载不出来 - HaoKunT的博客 将Elementary OS装在U盘中 - HaoKunT的博客 MacOS+Windows 双系统的安装 - HaoKunT的博客 IPXE+netboot+ISCSI 网络启动 - HaoKunT的博客 Esxi+NAS+Openwrt - HaoKunT的博客 Esxi的安装和使用 - HaoKunT的博客 利用acme自动更新证书 - HaoKunT的博客 Filetools工具 - HaoKunT的博客 学习正则表达式 - HaoKunT的博客 Vugu View - HaoKunT的博客 Django Restframework 嵌套序列化 - HaoKunT的博客 看不了netlify的部署日志 - HaoKunT的博客 Go Modules的使用 - HaoKunT的博客 使用hugo+netlify部署个人主页 - HaoKunT的博客 关于我 - HaoKunT的博客 在线工具大全 - HaoKunT的博客 SWIG编译海康威视SDK 使用golang - HaoKunT的博客 SWIG 以Python为例 - HaoKunT的博客 Seafile - HaoKunT的博客 Golang的小技巧 - HaoKunT的博客 归档 - HaoKunT的博客 搜索 - HaoKunT的博客
Golang使用海康威视SDK - HaoKunT的博客
HaoKunT · 2019-09-13 · via HaoKunT的博客

本文为原创文章,转载注明出处,欢迎关注网站https://hkvision.cn

接上一篇文章SWIG编译海康威视SDK-使用golang,这篇文章讲述的是如何使用编译好的文件,这涉及到SWIG和golang结合的问题

引入

编译好了之后.a文件会出现在GOPATH下,直接在import里面引入hikvision就可以了,build的时候会自动找到对应的.a文件

使用

下面从两个方面来介绍

  • golang中已有的类型对应关系
  • C里面typedef的值的对应关系,例如海康威视有BOOL,DWORD

golang中已有的类型对应关系

这里说的已有的类型是指在C语言中已经有了,比如说int,char*等,具体的对应关系表网上有很多,SWIG在这里的策略和cgo是一样的,这里给一个链接。这里就不多说了,在函数调用的时候可以直接把对应的go值传进去而不需要转换

C里面typedef的值的对应关系

这里主要来说这个问题

由于海康威视的SDK大量使用了typedef(应该是为了解决跨平台编译的问题),导致很多函数的返回值,参数值都不是正常的C类型,再加上大量的结构体,像我这样的菜鸟一开始根本无从下手,后来仔细看了SWIG生成的wrapper文件和搜索引擎了一番,才弄明白SWIG的逻辑。

SWIG的实现其实就是调用了cgo,只是他给你封装了一层,你如果弄明白了cgo的逻辑,那SWIG的逻辑也就不难理解了。

Swigcptr uintptr unsafe.Pointer

这是核心,这三个东西构成了所有的C和go直接的类型交互。首先介绍一下C和go之间进行参数传递的流程

digraph G {

  node [width=3]

  a0 [label="go值"]
  a1 [label="go野指针"]
  a2 [label="内存地址的uint值"]
  a3 [label="C指针"]

	subgraph cluster_go2c {
		style=filled;
		a0 -> a1 [label=" unsafe.Pointer"];
    a1 -> a2 [label=" uintptr"]
    a2 -> a3 [label=" Swigcptrxxx"]
		label = "Go to C";
	}

  b0 [label="C指针"]
  b1 [label="内存地址的uint值"]
  b2 [label="go野指针"]
  b3 [label="go值"]

	subgraph cluster_c2go {
    style=filled;
		b0 -> b1 [label=" Swigcptr"];
    b1 -> b2 [label=" unsafe.Pointer"]
    b2 -> b3 [label=" 指针转换"]
		label = "C to Go";
	}
}

这里的Swigcpterxxx后面的xxx对应的类型名称,Swig会自动帮我们生成这个函数。

整个的核心在于unsafe.Pointer函数,这个函数接收一个指针类型的变量(也可以接收uintptr类型的值),输出的是一个指针,但是对于go来说,这个指针已经变成了类似于野指针的存在,也就是说go不再承认这个指针是go体系里面的内容,gc也不会回收这块内存,需要我们自行管理。这个指针和C里面的void指针类似,代表这个指针可以指向任何一块内存。因此可以将这个指针对应的uint值(内存地址都可以用uint类型的变量来存储,这是一个特殊的类型,在GO和C中是uintptr,本质和uint是一样的)传递到C中。C的值传递到GO也是一样的过程,都是通过void*类型和unsafe.Pointer类型的值可以互传来实现的。

多重指针

在海康威视的SDK中有一种类型本身就是指针,例如LPVOID,那么使用SWIG编译后,对于GO程序而言,同样要用多重指针的思路来解决。

多重指针和单指针是一样的道理,在将GO值传递到C之前,我们首先要将这个值转化为多重指针,然后再进行上述步骤,这样海康威视SDK拿到的值才是正确的,不然就会报错。我也是实验了很多次才发现这个问题的,其实应该一开始就明白这个问题,还是基础不够扎实,没能一眼看明白。

下面是一个示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
lpOutBuffer_t := hk.NewNET_DVR_DIGITAL_CHANNEL_STATE()
defer hk.DeleteNET_DVR_DIGITAL_CHANNEL_STATE(lpOutBuffer_t)
dwCommand_t := hk.NET_DVR_GET_DIGITAL_CHANNEL_STATE

// 注意这里的转换与下面的转化的不同
lpOutBuffer_p := unsafe.Pointer(lpOutBuffer_t.Swigcptr())
lpOutBuffer := hk.SwigcptrLPVOID(uintptr(unsafe.Pointer(&lpOutBuffer_p)))

// 注意这里只用了一次`unsafe.Pointer`函数
dwCommand := hk.SwigcptrDWORD(uintptr(unsafe.Pointer(&dwCommand_t)))

这是截取的代码的一小部分,这里我是需要调用海康威视的NET_DVR_GetDVRConfig函数,这个函数有一个参数即为LPVOID类型,就是lpOutBuffer这个变量,实际上这个变量的值类型是NET_DVR_DIGITAL_CHANNEL_STATE,大家可以看到,这里首先在在创建一个NET_DVR_DIGITAL_CHANNEL_STATE类型后,先用Swigcptr函数拿到变量对应的地址,然后用两次unsafe.Pointer函数,然后才转成LPVOID,其余的变量我们只转换了一次。

函数调用

函数调用非常简单,当我们用unsafe.Pointer组织好各个参数后,直接调用即可,注意返回值也需要进行转换,这里就是进行逆转换了,对于海康威视SDK,大家可以写一个公共函数来进行转换,这样方便调用。