Maison > développement back-end > Tutoriel Python > La valeur de retour lorsque Python appelle le SDK C ne répond pas aux attentes et la solution à l'erreur de segmentation

La valeur de retour lorsque Python appelle le SDK C ne répond pas aux attentes et la solution à l'erreur de segmentation

高洛峰
Libérer: 2017-03-20 11:04:10
original
2058 Les gens l'ont consulté

1、sdk返回值不是int型

1.1 登录函数调用

def login (ip, port, nom d'utilisateur, mot de passe, 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 nom d'utilisateur :
:param mot de passe :
: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, nom d'utilisateur, mot de passe, 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 错误原因

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

15.17.1.8. Types de retour

Par défaut, les fonctions sont supposées renvoyer le type C int. D'autres types de retour peuvent être spécifiés en définissant l'attribut restype de la fonction object.

Voici un exemple plus avancé, il utilise la fonction strchr, qui attend un string pointeur et un caractère, et renvoie un pointeur vers une chaîne :

>>> 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
>>>
Copier après la connexion

1.3.2 修改

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

SDK._dll.CLIENT_Login.restype = c_longlong

 

2、回调函数场景下大概率出现Segment défaut de ation

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

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()
Copier après la connexion
Copier après la connexion
_buf_cond.acquire()
Copier après la connexion
_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()
Copier après la connexion

 

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)
Copier après la connexion
def set_callback(self, save_after_recv_pic, index):
    self.dll.CLIENT_SetSnapRevCallBack(self._callback(save_after_recv_pic), index)
Copier après la connexion
子类中定义,_save_after_recv_pic也在子类中定义为staticmethod
Copier après la connexion
def _set_callback(self):
    try:
        if 0 <= self.index < _buf_size:
Copier après la connexion
            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
Copier après la connexion
 <br>
Copier après la connexion

2.2.2 修改后问题解决

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

self.capture_callback = self.callback(self._save_after_recv_pic)
Copier après la connexion
子类中直接注册回调函数
Copier après la connexion
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
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal