1、sdk返回值不是int型 1.1 登錄函數調用 def login(ip, port, username, password, device_info, error_code):"""LLONG CLIENT_Login(char *pchDVRIP, WORD wDVRPort,char *p... ...
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