Python调用Linux c库:cty

2023-01-31 02:01:18 python 调用 cty

   我在Http://jlnsQt.blog.51cto.com/2212965/1405052这篇博客中讲述了匹配URL的一个算法,因项目需要将其封装为动态库,并让python组调用,所以研究了一下ctypes,感觉超级棒,必须记录下来。


   首先介绍一下我的动态库接口。

   动态库结构体:

   
typedef struct _whitelist_tree_node_ {
    uint8_t white_type; //匹配白名单是否结束,代表下一步执行的动作
    uint8_t child_count;                //该节点的子节点个数
    uint8_t child_order[MAX_CHILDS_NUM]; //子节点在childs的位置(起始1)
    struct _whitelist_tree_node_ *childs;   //子节点数组
} whitelist_tree_node;
typedef struct _whitelist_tree_ {
    whitelist_tree_node *root;          //根节点
    unsigned int whitelist_count;       //URL白名单个数
} whitelist_tree, *PUrlWhiteListControl;
                                                                                                                                                                                                                                                                                                                                                    
函数接口:

int InitUrlWhiteList(const char *ini_file, PUrlWhiteListControl *p_control);

int SearchUrlWhiteList(const char *url, PUrlWhiteListControl p_control);


void CloseUrlWhiteList(PUrlWhiteListControl p_control);


   这里不再给出生成动态库方法和各个接口函数的定义,只介绍如何在Python中调用。这里假设我动态库的名称为“liburlwhitelist.so”,动态库和python文件在同一目录,或者再引用动态库的时候用绝对路径。

   开始使用ctypes之前,介绍一下ctypes的类型对照:

ctypes typeC typePython type
c_bool_Boolbool (1)
c_charchar1-character string
c_wcharwchar_t1-character unicode string
c_bytecharint/long
c_ubyteunsignedcharint/long
c_shortshortint/long
c_ushortunsignedshortint/long
c_intintint/long
c_uintunsignedintint/long
c_longlongint/long
c_ulongunsignedlongint/long
c_longlong__int64 or longlongint/long
c_ulonglongunsigned__int64 or unsignedlonglongint/long
c_floatfloatfloat
c_doubledoublefloat
c_longdoublelongdoublefloat
c_char_pchar* (NUL terminated)string or None
c_wchar_pwchar_t* (NUL terminated)unicode or None
c_void_pvoid*int/long or None


   首先导入ctypes:


from ctypes import *

   定义最大子节点个数,也即静态数组的大小。    

#max child node number
MAX_NODE_CHILD_NUM = 46

   下面就是重点了,需要用python模拟出linux C的结构体来。


#define tree node
class whitelist_tree_node(Structure):
    pass
whitelist_tree_node._fields_ = [
    ("white_type", c_ubyte),
    ("child_count", c_ubyte),
    ("child_order", c_ubyte * MAX_NODE_CHILD_NUM),
    ("childs", POINTER(whitelist_tree_node))
]
#define tree
class whitelist_tree(Structure):
    pass
whitelist_tree._fields_ = [
    ("root", POINTER(whitelist_tree_node)),
    ("whitelist_count", c_uint)
]
#define query url whitelist control
PUrlWhiteListControl = POINTER(whitelist_tree)

   为了定义节点指向自己的指针,这里必须先用pass定义一个空的对象,否则会出现“NameError: name 'whitelist_tree_node' is not defined”的错误。取类型的指针用POINTER()函数,而取变量对象的指针用pointer()函数,注意区分。


   导入库,可用绝对路径:    

#load library
url_whitelist_lib = cdll.LoadLibrary("./liburlwhitelist.so")


   引入接口函数,并对接口函数属性进行设置。    

#define init function
InitUrlWhiteList = url_whitelist_lib.InitUrlWhiteList
#define argument types
InitUrlWhiteList.argtypes = [POINTER(PUrlWhiteListControl)]
#define return types. By default functions are assumed to return the C int type
InitUrlWhiteList.restype = c_int
                                                                                                                                                                                        
#define search function
SearchUrlWhiteList = url_whitelist_lib.SearchUrlWhiteList
SearchUrlWhiteList.argtypes = [c_char_p, PUrlWhiteListControl]
SearchUrlWhiteList.restype = c_int
                                                                                                                                                                                        
#define close function
CloseUrlWhiteList = url_whitelist_lib.CloseUrlWhiteList
CloseUrlWhiteList.argtypes = [PUrlWhiteListControl]
CloseUrlWhiteList.restype = None

   定义每个函数第一行“InitUrlWhiteList =url_whitelist_lib.InitUrlWhiteList”是为了减少函数调用。InitUrlWhiteList.argtypes设置函数的参数,为了更好的调用,减少出错。

InitUrlWhiteList.restype设置函数的返回类型,因为ctypes默认的返回类型时C int,我这里还是指出,便于统一和减少出错。


   使用部分例子:

p_control = PUrlWhiteListControl()
ret_code = InitUrlWhiteList(None, pointer(p_control))
if ret_code != 0:
    print "InitUrlWhiteList error code: %d" % ret_code
else:
    print "init url whitelist num: %u" % p_control.contents.whitelist_count

   这里有三个地方需要注意。一、None变量即是C中NULL。二:InitUrlWhiteList参数,因其第二个参数为PUrlWhiteListControl的指针,所以这里用pointer()函数,当然也可用byref()函数,但是在官方文档中指出:

The same effect can be achieved with the pointer() function, although
pointer() does a lot more work since it constructs a real pointer
object, so it is faster to use byref() if you don’t need the pointer
 object in Python itself

   所以这里我们还是用pointer()函数好。三、因PUrlWhiteListControl本身是一个指针,要访问他的内容需要用contents方法。如“p_control.contents.whitelist_count”。


   好了,关于ctypes,先介绍到这里,更详细的请参考官方文档:https://docs.python.org/2/library/ctypes.html。详细代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: sqt
# @Email:  qingtao_shang@vulnhunt.com
# @Date:   2014-04-30 09:57:37
# @Desc:   Python测试URL白名单动态库
# @Last Modified by:   sqt
# @Last Modified time: 2014-04-30 13:30:17
               
from ctypes import *
               
#max child node number
MAX_NODE_CHILD_NUM = 46
               
#define tree node
class whitelist_tree_node(Structure):
    pass
               
whitelist_tree_node._fields_ = [
    ("white_type", c_ubyte),
    ("child_count", c_ubyte),
    ("child_order", c_ubyte * MAX_NODE_CHILD_NUM),
    ("childs", POINTER(whitelist_tree_node))
]
               
#define tree
class whitelist_tree(Structure):
    pass
               
whitelist_tree._fields_ = [
    ("root", POINTER(whitelist_tree_node)),
    ("whitelist_count", c_uint)
]
               
#define query url whitelist control
PUrlWhiteListControl = POINTER(whitelist_tree)
#load library
url_whitelist_lib = cdll.LoadLibrary("./liburlwhitelist.so")
               
#simple call function name
#define init function
InitUrlWhiteList = url_whitelist_lib.InitUrlWhiteList
#define argument types
InitUrlWhiteList.argtypes = [POINTER(PUrlWhiteListControl)]
#define return types. By default functions are assumed to return the C int type
InitUrlWhiteList.restype = c_int
               
#define search function
SearchUrlWhiteList = url_whitelist_lib.SearchUrlWhiteList
SearchUrlWhiteList.argtypes = [c_char_p, PUrlWhiteListControl]
SearchUrlWhiteList.restype = c_int
               
#define close function
CloseUrlWhiteList = url_whitelist_lib.CloseUrlWhiteList
CloseUrlWhiteList.argtypes = [PUrlWhiteListControl]
CloseUrlWhiteList.restype = None
               
#sample
if __name__ == "__main__":
    p_control = PUrlWhiteListControl()
    ret_code = InitUrlWhiteList(None, pointer(p_control))
    if ret_code != 0:
        print "InitUrlWhiteList error code: %d" % ret_code
    else:
        print "init url whitelist num: %u" % p_control.contents.whitelist_count
                
    url = ""
    while 1:
        url = raw_input("Input url or exit:")
        if url == "q" or url == "exit":
            break
               
        find_code = SearchUrlWhiteList(url, p_control)
        if find_code == 0:
            print "url: %s find." % url
        else:
            print "url: %s not find." % url
                
    CloseUrlWhiteList(p_control)
    del p_control


相关文章