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
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
用户ID作为句柄,传入其他SDK函数中,报错,句柄无效。查看出现负值。因此怀疑是类型不匹配
网上查了下,并看了下文档,py thon中调用C的sdk,默认返回的是int型,按照login C版本的函数定义,返回的是LLONG型
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 >>>
设置sdk函数的返回值为c_longlong,问题解决
SDK._dll.CLIENT_Login.restype = c_longlong
网上找了一圈,一般两种可能性:内存越界或者读写非法;还有一种就是函数调用栈太深。
代码本身就添加了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()
由于引入这个sdk之后,使用了回调函数。因此将回调函数定义层次减少。
传入函数给基类,在基类中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
<br>
子类中直接实例化回调函数
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
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!