利⽤python3的ctypes库实现动态库so的调⽤
核⼼关注点在于通过python来处理C函数的⼊参与出参
动态库和调⽤的系统版本要匹配:
dll动态库需要在windows环境下运⾏,32bit的so动态库需要在32bit的linux环境下⾯调⽤,64bit的so动态库需要在64bit的linux环境下⾯调⽤
否则,报错:
Traceback (most recent call last):
File "cdll_so_s1ap_initialUE.py", line 85, in <module>
sotest = cdll.wd()+ "/look.so")
File "/usr/local/lib/python3.6/ctypes/__init__.py", line 426, in LoadLibrary
return self._dlltype(name)
File "/usr/local/lib/python3.6/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: /home/look.so.so: wrong ELF class: ELFCLASS32
原因:
Python 的 ctypes 要使⽤ C 函数,需要先将 C 编译成动态链接库的形式,即 Windows 下的 .dll ⽂件,或者 Linux 下的 .so ⽂件。先来看⼀下 ctypes 怎么使⽤ C 标准库。
Windows 系统下的 C 标准库动态链接⽂件为 msvcrt.dll (⼀般在⽬录 C:\Windows\System32 和 C:\Windows\SysWOW64 下分别对应 32-bit 和 64-bit,使⽤时不⽤刻意区分,Python 会选择合适的)
Linux 系统下的 C 标准库动态链接⽂件为 libc.so.6 (以 64-bit Ubuntu 系统为例, 在⽬录 /lib/x86_64-linux-gnu 下
⼀、动态库编译(C语⾔):
#ifdef _WIN_
#define DllExport __declspec( dllexport )
#else
#define DllExport __attribute ((visibility("default")))
#endif
DllExport int lookup(BYTE *in, WORD in_len, DWORD dwStartBit, BYTE *out, DWORD *out_len, BYTE bDir, CHAR *key)
⼆、导出符号表(eg:Linux):
nm -D look.so
在符号表中,可以看到第⼀步中C语⾔的导出函数。
三、出参处理(BYTE *out):
Python 默认的 string 是不可变的,所以不能传递 string 到⼀个 C 函数去改变它的内容,所以需要使⽤ create_string_buffer,对应Unicode 字符串,要使⽤ create_unicode_buffer,
C常规参数类型与ctypes、python类型对应关系表如下:
四、实例源码:
#! /usr/bin/env/python
# _*_ encoding : utf-8 _*_
from ctypes import *
import platform
import os, re
def getSpace(level):
space='\n'
for i in range(level):
space=space+' '
return space
# 格式化 XML 字符串#
def printXml(xml_str):
def printXml(xml_str):
#xml_list=xml_str.split('([>])')
new_xml_list=""
# head=xml_str[0:9]
# xml_str=xml_str[9:]
xml_list=re.split(r'([>])',xml_str)
xml_list = ["".join(i) for i in zip(xml_list[0::2],xml_list[1::2])]
level=0
for node in xml_list:
if(re.match(r'<\?xml .*version.*\?>',node)):
new_xml_list=new_xml_list+new_xml_list+node
continue
elif(re.match(r'<[^\?^/].*[^/]>',node)):
new_xml_list=new_xml_list+getSpace(level)+node
level=level+1
continue
elif(re.match(r'</.*[^/]>',node)):
level=level-1
new_xml_list=new_xml_list+getSpace(level)+node
continue
elif(re.match(r'<[^/].*/>',node)):
new_xml_list=new_xml_list+getSpace(level)+node
elif(re.match(r'.+</.*[^/]>',node)):
new_xml_list=new_xml_list+node
level=level-1
else:
print(node)
# print(new_xml_list)
return new_xml_list
def writeXML(outputstrt, xmlFileName):
fileHandle = open(xmlFileName, 'w',encoding="utf_8_sig")
fileHandle.write('')
fileHandle.close()
fileHandle = open(xmlFileName, 'a',encoding="utf_8_sig")
fileHandle.write(outputstrt + '\n\n')
fileHandle.close()
if __name__ == '__main__':
# key = "123456789" # 暂时随便写⼀个
# key_str = "E7 AB 8B E6 B0 91 E5 9B BD E4 BB AC E6 88 91 E4 B8 AD E4 BA BA E4 B8 BA E4 BA 86 E5 BB BA E4 B8" # 暂时随便写⼀个 key_str = '07 41 01 08 49 06 11 99 09 20 00 00 05 F3 72 40 30 00 00 05 52 00 D0 11 D1'
bitstream_Str = '01 00 01 38 00 00 00 00 12 00 30 10 80 08 64 10 91 99 00 32 11 F2 02 01 05 83 01 01'
# 输⼊码流的预处理
input_len = len(place(" ", '')) // 2
bitstream_list = bitstream_Str.split(' ')
input = (c_char * input_len)()
for i in range(input_len):
input[i] = int(bytes(bitstream_list[i], encoding='utf-8'),16)
print(int(bytes(bitstream_list[i], encoding='utf-8'),16))
in_p = bytes(bytearray(input))
key_len = len(place(" ", '')) // 2
key_list = key_str.split(' ')
key = (c_char * key_len)()
for i in range(key_len):
key[i] = int(bytes(key_list[i], encoding='utf-8'),16)
print(int(bytes(key_list[i], encoding='utf-8'),16))
key_p = bytes(bytearray(key))
key_p = bytes(bytearray(key))
# 打开 .so ⽂件
sotest = cdll.wd()+ "/XML.so")
sotest.argtypes = [c_char_p, c_ushort, c_uint, c_ubyte, c_uint, c_ubyte, c_ubyte, c_ubyte, c_char_p, c_char_p, c_ubyte, c_char_p] # 声明C函数的所有⼊参 stype=[c_int] # 声明C函数的返回值类型
buffer = create_string_buffer(8000000) # 创建可⽤于修改的出参
buffer_len = c_int() # 定义出参的长度变量
print("\n--------------------------------so打印结果输出-------------------------------------\n")
result = sotest.PubDecode(in_p, #BYTE *in
input_len, #WORD in_len
0, #DWORD dwStartBit+
9, #BYTE bModType
1325056, #DWORD msgType
3, #BYTE msgVersion
0, #BYTE bDir 1 - receive 0 - send
0, #BYTE bNetType
buffer, #BYTE *out
byref(buffer_len), # DWORD *out_len
0, #BYTE isAnony
key_p) #CHAR *key
print("\n--------------------------------py调试结果输出-------------------------------------\n")
wd()+ "/XML.so")
print("\n******--------input--------******")
print("input_len: " + str(input_len))
print("bitstream_Str: " + place(" ", ''))
print(in_p)
print(bitstream_list)
print("\n******--------result--------******")
print("result: %d 0-ok 1-failed" % result)
print("\n******--------output--------******")
print("out_len: " + str(buffer_len.value))
print("\n------------------")
print(str(buffer.value).replace(r'\n', '').replace(r'\r', '').split("'")[1])
python处理xml文件print("\n--------------------------------结果输出到⽂件-------------------------------------\n")
writeXML(printXml(str(buffer.value).replace(r'\n', '').replace(r'\r', '').split("'")[1]), '')
五、reference:
格式化XML字符串
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论