python调用c的sdk出现返回值不符合预期以及segmentationfault的解决方法

1、sdk返回值不是int型1.1 登录函数调用

def login(ip, port, username, password, device_info, error_code):”””llong client_login(char *pchdvrip, word wdvrport,char *pchusername, char *pchpassword,lpnet_deviceinfo lpdeviceinfo, int *error = 0);:param ip::param port::param username::param password::param device_info::param error_code::return: llong”””ip_buffer = c_buffer(ip)# ip_buffer.encode(‘utf8’)# user_id = c_longlong(0)user_id = sdk._dll.client_login(byref(ip_buffer), port, username, password, byref(device_info), byref(error_code))return user_id # c_longlong(user_id).value

1.2 无效的id

用户id作为句柄,传入其他sdk函数中,报错,句柄无效。查看出现负值。因此怀疑是类型不匹配

1.3 设置返回类型1.3.1 错误原因

网上查了下,并看了下文档,python中调用c的sdk,默认返回的是int型,按照login c版本的函数定义,返回的是llong型

15.17.1.8. return types

by default functions are assumed to return the c int type. other return types can be specified by setting the restype attribute of the function object.

here is a more advanced example, it uses the strchr function, which expects a string pointer and a char, and returns a pointer to a string:

>>> strchr = libc.strchr
>>> strchr(“abcdef”, ord(“d”))
8059983
>>> strchr.restype = c_char_p # c_char_p is a pointer to a string
>>> strchr(“abcdef”, ord(“d”))
‘def’
>>> print strchr(“abcdef”, ord(“x”))
none
>>>1.3.2 修改

设置sdk函数的返回值为c_longlong,问题解决

sdk._dll.client_login.restype = c_longlong

2、回调函数场景下大概率出现segmentation fault

网上找了一圈,一般两种可能性:内存越界或者读写非法; 还有一种就是函数调用栈太深。

2.1 读写加锁

代码本身就添加了condition读写锁得,buf也是在写的时候分配的,多番调试,应该不是这个地方因为的问题。打印日志看,也与读写操作无关。

index = userdata # c_uint(userdata).value
_buf_cond.acquire()
# time.sleep(0.2)
# 复制图片到内存
# _pic_buf.buf = pbuf c_char 和 c_byte转换
try:
temp = [pbuf[i] for i in xrange(0, revlen)]
_buf_list[index].buf = struct.pack(‘%db’ % revlen, *temp)
# 序列号
_buf_list[index].sn = c_ulong(cmdserial).value
_buf_list[index].id = index
_buf_list[index].size = c_uint(revlen).value
_buf_list[index].ext = ‘jpeg’ # encode_dict.get(encodetype, ‘jpeg’)
except exception, e:
logger.error(‘截图缓存发生异常:%s’ % str(e))
finally:
_buf_cond.notify()
_buf_cond.release()读_buf_cond.acquire()_buf_cond.wait(timeout=15.0)
# 等待200ms再访问数据
# time.sleep(0.2)
if _buf_list[self.index].sn == snap.cmdserial and _buf_list[self.index].id == self.index:
self.save_picture(_buf_list[self.index].buf, _buf_list[self.index].ext)
self.info(‘针对通道%d截图成功,ip:%s,port:%s’ % (channel, self.ip, self.port))
pass
_buf_cond.release()

2.2 减少栈调用层次

由于引入这个sdk之后,使用了回调函数。因此将回调函数定义层次减少。

2.2.1 修改前

传入函数给基类,在基类中cfunctype实例化函数

基类中定义

self.callback = cfunctype(c_void_p, c_longlong, pointer(c_byte), c_uint, c_uint, c_ulong, c_ulonglong)def set_callback(self, save_after_recv_pic, index):
self.dll.client_setsnaprevcallback(self._callback(save_after_recv_pic), index)子类中定义,_save_after_recv_pic也在子类中定义为staticmethoddef _set_callback(self):
try:
if 0

Posted in 未分类

发表评论