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


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

    image

    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
    好记性不如烂笔头
  • 相关阅读:
    springMVC:HandlerInterceptor拦截器的使用
    SpringMVC:JSON形式输出(基于Fastjson)
    Callable接口解析
    FastJson一些常见方法(API):处理JSON变得好简单
    Spring@Autowired注解
    一些错误和解决办法--01
    线程池的原理及实现
    Rotate Image(二位数组顺时针旋转)
    JAVA内部类
    jdk9模块化--特性
  • 原文地址:https://www.cnblogs.com/inns/p/6209504.html
Copyright © 2020-2023  润新知