最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
当前位置: 首页 - 科技 - 知识百科 - 正文

Python调用C的SDK出现返回值不符合预期以及Segmentationfault的解决方法

来源:懂视网 责编:小采 时间:2020-11-27 14:16:16
文档

Python调用C的SDK出现返回值不符合预期以及Segmentationfault的解决方法

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
推荐度:
导读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

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函数中,报错,句柄无效。查看出现负值。因此怀疑是类型不匹配

Python调用C的SDK出现返回值不符合预期以及Segmentation fault的解决方法

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

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文档

Python调用C的SDK出现返回值不符合预期以及Segmentationfault的解决方法

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
推荐度:
标签: 出现 解决 python
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top