def run(self): try: print('PID--task_controler:', os.getpid()) mylogger.info('PID--task_controler: %d' % os.getpid()) thread_conn = threading.Thread(target=self._monitorconn) thread_send = threading.Thread(target=self._get_push_data) thread_conn.daemon = True thread_send.daemon = True thread_conn.start() thread_send.start() print('start task') thread_conn.join() print('stop task controler') mylogger.error('task controler was stop') except KeyboardInterrupt: # while self.sock is not None: # print(self.server_sock) # self.server_sock.shutdown(socket.SHUT_RDWR) # self.server_sock.close() # time.sleep(2) print('self.sock', self.sock) except Exception as e: print('task_controler was stop by exception: ', e) mylogger.error('task_controler was stop by exception:' + e) print('\033[1;33m', 'task_controler was stop', '\033[0m') mylogger.error('task_controler was stop')
def init_sdk(self): init_res = self.call_cpp("NET_DVR_Init") # SDK初始化 if init_res: mylogger.info("SDK初始化成功") return True else: self.print_error( "NET_DVR_GetLastError 初始化SDK失败: the error code is") return False
def run(self): """ 1、主动连接所有已注册服务端; 2、监听等待连接所有已注册客户端; 3、打开注册子线程; 4、打开创建与监测子线程; 5、打开交互接口。 :return: """ try: print('PID--gateway_server:', os.getpid()) mylogger.info('PID--gateway_server: %d' % os.getpid()) # connect all servers if self.servers is not None: print("Start to connect to registered servers!!!!") for k, v in self.servers.items(): self._connect_server(addr=k, ttype=v[0], storeroom_id=v[1], uuid=v[2]) else: mylogger.info( 'There is None registered server for connecting!') # monitor and reconn servers thread_reconn_server = threading.Thread( target=self._reconnect_offline_server) thread_reconn_server.daemon = True thread_reconn_server.start() # listen all access clients thread_monitor_client = threading.Thread( target=self._monitor_access) thread_monitor_client.daemon = True thread_monitor_client.start() # monitor status subthread on time self.check_interval = conpar.read_yaml_file( 'configuration')['gateway_server_check_interval'] t = threading.Timer(interval=self.check_interval, function=self._thread_ontime) t.daemon = True t.start() # wait for cmd print('gateway server was start') while self.isrunning: self._handle_cmd() time.sleep(1) print('gateway server was stop') mylogger.error('gateway server was stop') except Exception as e: print('gateway server was stop by exception: ', e) mylogger.error('gateway server was stop by exception:' + e) print('\033[1;33m', 'gateway_server was stop', '\033[0m') mylogger.error('gateway_server was stop')
def _analyze_web_pkg(self, package: dict): """ 1、gateway_server与设备的控制指令,不经过处理直接放入队列下发; 2、其他指令进行包分析处理; :param package: :return: """ if package['msg_type'] == 0 or package['msg_type'] == 1: mylogger.info('get pkg from webserver') self.puttask(package) else: self._analyze_pkg(package=package)
def run(self): """ 1、主动连接所有已注册服务端; 2、监听等待连接所有已注册客户端; 3、打开注册子线程; 4、打开创建与监测子线程; 5、打开交互接口。 :return: """ try: # connect all servers if self.servers is not None: print("Start to connect to registered servers!!!!") for k, v in self.servers.items(): self._connect_server(addr=k, ttype=v[0], storeroom_id=v[1], uuid=v[2]) else: mylogger.info( 'There is None registered server for connecting!') # monitor and reconn servers thread_reconn_server = threading.Thread( target=self._reconnect_offline_server) thread_reconn_server.daemon = True thread_reconn_server.start() # listen all access clients thread_monitor_client = threading.Thread( target=self._monitor_access) thread_monitor_client.daemon = True thread_monitor_client.start() # monitor status subthread on time t = threading.Timer(interval=1, function=self.time_thread) t.daemon = True t.start() # wait for cmd while True: with self.lock: status = self.isrunning if status: self._handle_cmd() else: break except Exception as e: print('gateway_server: ', e) mylogger.error(e)
def _monitorconn(self): server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) addr = ('', 9999) server_sock.bind(addr) server_sock.listen(1) self.server_sock = server_sock while self.isrunning: try: while True: print('waitting for new web connection') client_sock, addr = server_sock.accept() self.sock = client_sock print('new conn: ', addr) break while True: # length_data = client_sock.recv(1024) length_data = client_sock.recv(4) if length_data == b'exit': break elif len(length_data) == 0: print('client: ', addr, ' was offline') raise BrokenPipeError else: # self.puttask(data=length_data) length = struct.unpack('i', length_data)[0] data = client_sock.recv(length) print(time.asctime(), 'recv: ', data) # 接收的data为bytes类型的json数据,其中的None会自动换成null,需要注意,此刻如果使用eval()转换会报错“null not defined” # data_dict = eval(str(data, encoding='utf-8')) data_dict = json.loads(data.decode().strip()) print('\033[1;34m', 'recv from web pkg--', data_dict, '\033[0m') mylogger.info('recv web pkg--%s' % str(data, encoding='utf-8')) self._analyze_web_pkg(data_dict) except (OSError, BrokenPipeError): continue except KeyboardInterrupt: print('monitor keyboard') break self.sock.send(b'exit') server_sock.shutdown() server_sock.close() print('\033[1;34m', 'tcp server shutdown', '\033[0m')
def ontime_progress_monitor(q_task, q_rsl): print('*********times out progress monitor**********') if not progress['gateway_server'].is_alive(): print('progress gateway_server is not alive') mylogger.error('progress gateway_server is not alive') rsl = get_all_equipments() servers_registered = dict() # {addr: (type, storeroom_id, uuid)} clients_registered = dict() for r_id, s_c in rsl.items(): temp_servers = { k: (v[0], r_id, v[1]) for k, v in s_c['servers'].items() } servers_registered.update(temp_servers) temp_clients = { k: (v[0], r_id, v[1]) for k, v in s_c['clients'].items() } clients_registered.update(temp_clients) myserver_demo = GatewayServer(port=8809, servers_registered=servers_registered, clients_registered=clients_registered, queue_task=q_task, queue_rsl=q_rsl) myserver_demo.daemon = True myserver_demo.start() progress['gateway_server'] = myserver_demo mylogger.info('progress gateway_server is start again') if not progress['task_controler'].is_alive(): print('progress task_controler is not alive') mylogger.error('progress task_controler is not alive') mycontroler_demo = TaskControler(queue_task=q_task, queue_rsl=q_rsl) mycontroler_demo.daemon = True mycontroler_demo.start() progress['task_controler'] = mycontroler_demo mylogger.info('progress task_controler is start again') thd_timer1 = threading.Timer(interval=60, function=ontime_progress_monitor, args=([q_task, q_rsl])) thd_timer1.start()
def _save_rfid_data(self, rfid_history: list): """ 1、逐个判断借出或者归还; 2、借出:若耗材则直接保存已还,否则直接保存未还并设置goods出库; 3、归还:是否在未还列表,是则修改已还并设置goods入库,否则新增记录设置错误用户已还并设置goods入库; :param history: :return: """ try: # print('rfid history--', history) current_dt = datetime.datetime.now() # 先把self.rfid_goods中的key从bytes转为str; rfid_current = {k.hex(): v for k, v in self.rfid_goods.items()} goods_registered = Goods.by_epc_list(epcs=list(rfid_current.keys())) goods_epc_db = {g.epc: g for g in goods_registered} epc_grid_history = {h.epc: h for h in rfid_history} if rfid_history is not None else {} for epc, v in rfid_current.items(): grid_current = Grid.by_eqid_antenna(eq_id=v[0], antenna_num=v[1].hex(), addr_num=v[3].hex()) grid_id_current = grid_current.id if grid_current is not None else None if epc in goods_epc_db.keys(): # 存在于DB的EPC if v[2] is True: # 为归还 if epc in epc_grid_history.keys(): # 该EPC在未还列表 goods_grid_id = goods_epc_db[epc].grid_id wrong_place_gid = grid_id_current if grid_id_current != goods_grid_id else None status = 3 if wrong_place_gid else 0 record = epc_grid_history[epc] if record: record.update('status', status) record.update('inbound_datetime', current_dt) record.update('wrong_place_gid', wrong_place_gid) else: if self.user_role == 1 or self.user_role == 2: # 管理员新增物资 record = History_inbound_outbound(user_id=self.user_id, grid_id=grid_id_current, epc=epc, count=1, inbound_datetime=current_dt, status=5) record.save() mylogger.info('EPC(%s) was increased by administrator--%s' % (epc, self.user_code)) else: # 普通用户代还 record = History_inbound_outbound(user_id=self.user_id, grid_id=grid_id_current, epc=epc, count=1, inbound_datetime=current_dt, status=4) record.save() mylogger.info('EPC(%s) was returned by wrong user--%s' % (epc, self.user_code)) else: # 为借出 goods = goods_epc_db[epc] status = 0 if goods.type == 2 else 1 record = History_inbound_outbound(user_id=self.user_id, grid_id=grid_id_current, epc=epc, count=1, outbound_datetime=current_dt, status=status) record.save() goods.update('is_in_store', 0) else: # 不存在于DB的EPC record = History_inbound_outbound(user_id=self.user_id, grid_id=grid_id_current, epc=epc, count=1, inbound_datetime=current_dt, status=6, wrong_place_gid=grid_id_current) record.save() mylogger.warning('EPC(%s) was not registered but token in by user--%s' % (epc, self.user_code)) except Exception as e: mylogger.warning(e)
def _save_gravity_data(self, history: list): """ 1、借出 1.1 有错放记录的格子 1.2 正常的格子 2、归还 2.1 已借未还的格子 2.2 无借却还的格子 :param history: :return: """ try: current_dt = datetime.datetime.now() # grids_history = [h.grid_id for h in history] for k, v in self.gravity_goods.items(): if v[1] < 0: # 为借出 print('\033[1;33m', 'take out weight %d' % v[1], '\033[0m') records_this_grid = [record for record in history if record.grid_id == k] is_wrong_place = False for record in records_this_grid: if record.status == 3: is_wrong_place = True if is_wrong_place: # 有错放记录的格子 if self.user_role == 1 or self.user_role == 2: msg = 'the wrong placed grid-%s was take out-%dg by administrator-%s' % (k, v[1], self.user_code) mylogger.info(msg=msg) else: # 普通用户借出 is_returned = False for g in self.gravity_goods.values(): if g[1] > 0 and abs(g[1] + v[1]) < self.gravity_precision: # 归还清单有对应的重量 is_returned = True rsl = History_inbound_outbound.by_user_grid_status3(user_id=self.user_id, grid_id=k) if rsl: for record in rsl: if abs(record.count + v[1]) < self.gravity_precision: # 清除该错放记录 record.update('status', 0) record.update('outbound_datetime', current_dt) if not is_returned: status = 0 if v[0] == 2 else 1 record = History_inbound_outbound(user_id=self.user_id, grid_id=k, count=abs(v[1]), outbound_datetime=current_dt, status=status, monitor_way=1) record.save() print('create a new record') else: # 没有错放记录的格子 status = 0 if v[0] == 2 else 1 record = History_inbound_outbound(user_id=self.user_id, grid_id=k, count=abs(v[1]), outbound_datetime=current_dt, status=status, monitor_way=1) record.save() else: # 为归还 print('\033[1;33m', 'put in weight %d' % v[1], '\033[0m') grid_id_need_return = [h.grid_id for h in history if (h.status == 1 or h.status == 2)] if k in grid_id_need_return: # 已借未还 records_this_grid = [record for record in history if record.grid_id == k and (record.status == 1 or record.status == 2)] remain = v[1] for record in records_this_grid: if record.return_mark is not None: # 尚未还清的记录 return_mark_dict = eval(record.return_mark) returned_count = sum(return_mark_dict.values()) need_return = record.count - returned_count diff = remain - need_return record.update('inbound_datetime', current_dt) return_mark_dict[current_dt.strftime("%Y-%m-%d-%H-%M-%S")] = need_return record.update('return_mark', str(return_mark_dict)) if diff >= -self.gravity_precision: # 该条记录全还清 record.update('status', 0) remain -= need_return else: # 该条记录只还部分,并结束该格子的归还 break else: # 未还过的记录 diff = remain - record.count record.update('inbound_datetime', current_dt) return_mark_dict = {current_dt.strftime("%Y-%m-%d-%H-%M-%S"): record.count} record.update('return_mark', str(return_mark_dict)) if diff >= -self.gravity_precision: # 该条记录全还清 record.update('status', 0) remain -= record.count else: # 该条记录只还部分,并结束该格子的归还 break print('remain--', remain) if remain > self.gravity_precision: # 归还后有超出重量的其他东西,记录为错放格子 record = History_inbound_outbound(user_id=self.user_id, grid_id=k, count=remain, monitor_way=1, inbound_datetime=current_dt, status=3, wrong_place_gid=k) record.save() msg = 'the grid-%s was returned by overweight-%dg by user-%s' % (k, v[1], self.user_code) mylogger.warning(msg=msg) else: # 无借却还 if self.user_role == 1 or self.user_role == 2: msg = 'the grid-%s was put in-%dg by administrator-%s' % (k, v[1], self.user_code) mylogger.info(msg=msg) record = History_inbound_outbound(user_id=self.user_id, grid_id=k, count=abs(v[1]), monitor_way=1, inbound_datetime=current_dt, status=5) record.save() # 修改该格子物资的新增字段 else: if grid_id_need_return: # 只要仍然有未还的记录,放错格子 record = History_inbound_outbound(user_id=self.user_id, grid_id=k, count=abs(v[1]), monitor_way=1, inbound_datetime=current_dt, status=3, wrong_place_gid=k) record.save() msg = 'the grid-%s was wrong placed weight-%dg by user-%s' % (k, v[1], self.user_code) mylogger.info(msg=msg) except Exception as e: mylogger.warning(e)
def _analyze_pkg(self, package: dict): """ 1、门禁事件: 查询是否存在该门禁的处理线程,存活的就放入pkg,否则创建开始新线程; 2、数据更新事件: 根据设备pkg中storeroom的ID号放入相应的线程; 3、其他推送到web的响应事件; :param package: :return: """ try: print('analyze pkg: ', package) # if self.sock: # data_send = bytes('{}'.format(package), encoding='utf-8') # self.sock.send(data_send) storeroom_id = package['storeroom_id'] if package['msg_type'] == 3 and package['equipment_type'] in (3, 5): print('111') # 门禁的数据更新pkg处理 if storeroom_id in self.storeroom_thread.keys() and self.storeroom_thread[storeroom_id]['thread'].isAlive(): self.storeroom_thread[storeroom_id]['queue'].put(package) else: print('\033[1;33m', package['data']['user'] + 'enter to storeroom--' + storeroom_id + ' by entrance--' + str(package['source']), '\033[0m') addr = package['source'] eq_id = package['equipment_id'] user_code = package['data']['user'] queue_storeroom = Queue(50) thread_store_mag = StoreroomManager(entrance_addr=addr, entrance_id=eq_id, user_code=user_code, queue_storeroom=queue_storeroom, q_send=self.q_rsl, q_task=self.q_task) thread_store_mag.daemon = True thread_store_mag.start() self.storeroom_thread[storeroom_id] = {'thread': thread_store_mag, 'queue': queue_storeroom} elif package['msg_type'] == 3: print('222') # 其他设备的数据更新pkg处理. 判断是否为重力,并更新DB的实时总重量;若有人在库,则放入库房处理程序; if package['equipment_type'] == 1: self._update_db_data(package=package) if storeroom_id in self.storeroom_thread.keys() and self.storeroom_thread[storeroom_id]['thread'].isAlive(): self.storeroom_thread[storeroom_id]['queue'].put(package) else: print('someone has not login but did something') path_cur = os.path.abspath(os.path.dirname(__file__)) playsound(path_cur + '/../util/a_o.mp3') elif package['msg_type'] == 2 and package['code'] == 301: print('333') # web确定按钮pkg if storeroom_id in self.storeroom_thread.keys() and self.storeroom_thread[storeroom_id]['thread'].isAlive(): self.storeroom_thread[storeroom_id]['queue'].put(package) # 等待线程结束信号并返回web else: # 此借还线程不存在,返回web信息不成功 package['code'] = TASK_HANDLE_ERR package['msg_type'] = 4 package['data'] = {'msg': 'the thread of storeroom is not alive'} if self.sock: # data_send = bytes('{}'.format(package), encoding='utf-8') print(type(package)) data_send = json.dumps(package).encode() length = len(data_send) # 定制包头 i为4个字节,所以接收方为四个字节,这个大小并不是输入的大小,而是封装固定的大小 data_length = struct.pack('i', length) # 使用struct,直接将int转为二进制型数据传输,对方使用struct解包 self.sock.send(data_length) self.sock.send(data_send) elif package['msg_type'] == 4 and package['source'] is None: print('444') # web response print('web response--', package) else: print('555') if self.sock: # data_send = bytes('{}'.format(package), encoding='utf-8') print(type(package)) data_send = json.dumps(package).encode() length = len(data_send) # 定制包头 i为4个字节,所以接收方为四个字节,这个大小并不是输入的大小,而是封装固定的大小 data_length = struct.pack('i', length) # 使用struct,直接将int转为二进制型数据传输,对方使用struct解包 self.sock.send(data_length) self.sock.send(data_send) print('\033[1;34m', 'send to web pkg--', data_send, '\033[0m') mylogger.info('send web pkg--%s' % str(data_send, encoding='utf-8')) except Exception as e: mylogger.error(e)
def _monitor_access(self): # 创建socket对象 server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_sock.bind(self.addr) # 监听请求 server_sock.listen() # 建立长连接 try: print('--等待客户端连接本服务器8809!--') while self.isrunning: client_sock, addr = server_sock.accept() # 每一个新client连接就会产生一个线程 queue_task = Queue(50) queue_rsl = Queue(50) subevent = threading.Event() thread = None client_type = self.clients[addr][ 0] if addr in self.clients.keys() else None storeroom_id = self.clients[addr][ 1] if addr in self.clients.keys() else None uuid = self.clients[addr][2] if addr in self.clients.keys( ) else None if client_type == 'gravity': gravity = Collector.by_addr(ip=addr[0], port=addr[1]) if gravity: addr_nums = gravity.node_addrs.replace(' ', '').split(',') thread = GravityShelf(addr, client_sock, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid, addr_nums) elif client_type == 'led': indicator = Indicator.by_addr(ip=addr[0], port=addr[1]) if indicator: addr_nums = indicator.node_addrs.replace(' ', '').split(',') thread = IndicatorLCD(addr, client_sock, queue_task, queue_rsl, subevent, storeroom_id, uuid, addr_nums) elif client_type == 'rfid2000': thread = RfidR2000(addr, client_sock, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid) elif client_type == 'rfid2000fh': r2000fh = Collector.by_addr(ip=addr[0], port=addr[1]) addr_nums = ['01'] if r2000fh: addr_nums = r2000fh.node_addrs.replace(' ', '').split(',') thread = RfidR2000FH(addr, client_sock, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid, addr_nums) elif client_type == 'channel_machine': r2000fh = Collector.by_addr(ip=addr[0], port=addr[1]) addr_nums = ['01'] if r2000fh: addr_nums = r2000fh.node_addrs.replace(' ', '').split(',') thread = ChannelMachineR2000FH(addr, client_sock, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid, addr_nums) else: pass if thread: thread.daemon = True thread.start() self.lock.acquire() self.terminal_active[addr] = { 'thread': thread, 'type': client_type, 'queuetask': queue_task, 'queuersl': queue_rsl, 'status': True, 'subevent': subevent, 'data': {}, 'is_server': False } self.client_active[addr] = client_type self.lock.release() mylogger.info('客户端(%s)已成功连接。。online' % str(addr)) self._modify_db_eq_status(eq_type=client_type, addr=addr, is_online=True) print('客户端(%s)已成功连接。。' % str(addr)) else: mylogger.info('客户端(%s)连接创建线程失败。。' % str(addr)) print('客户端(%s)连接创建线程失败。。' % str(addr)) finally: server_sock.shutdown(socket.SHUT_RDWR) server_sock.close()
def _connect_server(self, addr: tuple, ttype: str, storeroom_id: str, uuid: str): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(0.1) failed_count = 0 terminal_type = ttype queue_task = Queue(50) queue_rsl = Queue(50) subevent = threading.Event() thread = None while self.isrunning: try: if terminal_type == 'entrance_zk': thread = EntranceZK(addr, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid) elif terminal_type == 'entrance_hk': thread = HKVision(addr, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid) else: s.connect(addr) if terminal_type == 'gravity': gravity = Collector.by_addr(addr[0], addr[1]) if gravity: addr_nums = gravity.node_addrs.replace( ' ', '').split(',') thread = GravityShelf(addr, s, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid, addr_nums) elif terminal_type == 'led': thread = IndicatorLCD(addr, s, queue_task, queue_rsl, subevent, storeroom_id, uuid) elif terminal_type == 'rfid2000': thread = RfidR2000(addr, s, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid) elif terminal_type == 'rfid2000fh': r2000fh = Collector.by_addr(addr[0], addr[1]) addr_nums = ['01'] if r2000fh: addr_nums = r2000fh.node_addrs.replace( ' ', '').split(',') thread = RfidR2000FH(addr, s, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid, addr_nums) elif terminal_type == 'channel_machine': r2000fh = Collector.by_addr(addr[0], addr[1]) addr_nums = ['01'] if r2000fh: addr_nums = r2000fh.node_addrs.replace( ' ', '').split(',') thread = ChannelMachineR2000FH( addr, s, queue_task, queue_rsl, subevent, self.queue_equipment_push, storeroom_id, uuid, addr_nums) else: pass if thread: thread.setDaemon(True) thread.start() self.lock.acquire() self.terminal_active[addr] = { 'thread': thread, 'type': terminal_type, 'queuetask': queue_task, 'queuersl': queue_rsl, 'status': False, 'subevent': subevent, 'data': {}, 'is_server': True } self.server_active[addr] = (terminal_type, storeroom_id, uuid) self.lock.release() print('服务端(%s)已成功连接。。' % str(addr)) mylogger.info('服务端(%s)已成功连接。。online' % str(addr)) self._modify_db_eq_status(eq_type=terminal_type, addr=addr, is_online=True) break except socket.error: failed_count += 1 # print("fail to connect to server %d times" % failed_count) if failed_count == 10: print('fail to connect to server %s' % str(addr)) mylogger.warning('fail to connect to server %s' % str(addr)) break
myserver.start() mycontroler.start() mycontroler.join() # while True: # pass except KeyboardInterrupt: # mydb.close() # myserver.stop() mycontroler.stop() while mycontroler.is_alive(): time.sleep(1) print('thread is still alive') except Exception as e: print(e) mylogger.error(e) # finally: # mydb.close() # myserver.stop() # mycontroler.stop() # print('stop') def test(): get_epcs() if __name__ == '__main__': mylogger.info('START SERVER') main() # test()
mycontroler.start() progress['task_controler'] = mycontroler thd_timer = threading.Timer(interval=60, function=ontime_progress_monitor, args=([q_task, q_rsl])) thd_timer.start() thd_timer.join() except KeyboardInterrupt: mydb.close() myserver.stop() mycontroler.stop() thd_timer.cancel() while mycontroler.is_alive() or myserver.is_alive(): time.sleep(1) print('thread--mycontroler/myserver is still alive') except Exception as e: print('exception from main', e) mylogger.error('exception from main: %s' % e) # def test(): # get_epcs() if __name__ == '__main__': mylogger.info('START SYSTEM') print('PID--main:', os.getpid()) mylogger.info('PID--main: %d' % os.getpid()) main() print('SYSTOM IS OVER') mylogger.info('SYSTOM IS OVER')
def sdk_clean(self): result = self.call_cpp("NET_DVR_Cleanup") mylogger.info("释放资源, result=%d" % result) print("释放资源", result)
def logout(self, userId=0): result = self.call_cpp("NET_DVR_Logout", userId) mylogger.info("登出, result=%d" % result)