视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Python调用C的SDK出现返回值不符合预期以及Segmentationfault的解决方法
2020-11-27 14:16:16 责编:小采
文档


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也在子类中定义为staticmethod
def _set_callback(self):
 try:
 if 0 <= self.index < _buf_size:
 self.set_callback(self._save_after_recv_pic, self.index) # 函数调用层次太深,经常报segmentation fault
 return True
 else:
 self.error('设置截图保存回调函数的userdata参数错误:%d' % self.index)
 return False
 except Exception, e:
 self.error('设置截图保存回调函数失败,%s' % str(e))
 return False
 

2.2.2 修改后问题解决

子类中直接实例化回调函数

self.capture_callback = self.callback(self._save_after_recv_pic)
子类中直接注册回调函数
def _set_callback(self):
 try:
 if 0 <= self.index < _buf_size:
 self.dll.CLIENT_SetSnapRevCallBack(self.capture_callback, self.index)
 # self.set_callback(self._save_after_recv_pic, self.index) # 函数调用层次太深,经常报segmentation fault
 return True
 else:
 self.error('设置截图保存回调函数的userdata参数错误:%d' % self.index)
 return False
 except Exception, e:
 self.error('设置截图保存回调函数失败,%s' % str(e))
 return False

下载本文
显示全文
专题