def _responseForm(self, taskId: str, moles: list) -> None: # 上传接收命令的主机到redis表 field = '{}_response'.format(taskId) self.redisObj.redisPointer().sadd(field, *moles) printMsg = 'The task {} answer form has been logged -> {}.'.format(taskId, *moles) self.logObj.logHandler().info(printMsg) PrettyCode.prettyPrint(printMsg)
def heartbeat_packet_processing(self, *args, **kwargs): # 判断心跳信息 if not self.addr[0] in self.redisObj.redisPointer().smembers('exists'): # redis未查询到记录,添加新主机 self.redisObj.setAddData('exists', [self.addr]) self.logObj.logHandler().info('Online: {}'.format(self.addr)) PrettyCode.prettyPrint('已上线:{}'.format(self.addr)) PrettyCode.prettyPrint('正确应答:{} - {}'.format(self.addr, self.data))
def _udpSenderAllSurvive(self, udpSocket, msg: str, moles: list): """udp发包操作函数(所有存活客户端),只做发送操作。 Args: msg (str): 需要发送的信息。 moles (list): 需要发送的地址。 taskId (str): 任务ID。 """ for mole in moles: udpSocket.sendto(msg.encode('utf-8'), (mole, 6655)) self.logObj.logHandler().info('{} - Delivery is complete (all online hosts).'.format(mole)) PrettyCode.prettyPrint('{} - 下发完成 - 所有存活主机。'.format(mole))
def funcDaemon(self, threadSchedule: dict) -> None: """守护进程逻辑 Args: threadSchedule (dict): 需要持续监控的线程字典。 """ while 1: for tName, tFunc in threadSchedule.items(): if tName not in str(enumerate()): # 监测离线 self.logObj.logHandler().warning('Process terminated: {}.'.format(tName)) tFunc.start() printMsg = '{} 进程已重启。'.format(tName) self.logObj.logHandler().warning('Process restarted: {}'.format(tName)) PrettyCode.prettyPrint(printMsg) time.sleep(10)
def _udpSendDispatchMode(self, key: str, dispatchCommands: dict) -> str: """调度指令,传入命令上传redis,传入后下发key至客户端标记开始 Args: key (str): task ID dispatchCommands (dict): task Returns: str: task ID """ try: self.redisObj.redisPointer().zadd(key, dispatchCommands) PrettyCode.prettyPrint('任务已成功更新。') except Exception as e: errorMsg = '{} - {}'.format(e, e.__traceback__.tb_lineno) self.logObj.logHandler().error(errorMsg) return key
def __init__(self): # 初始化 self.config= None self._loadingConfig() # 重传超时时间 self.rto = 3 # 实例化日志 self.logObj = BasicLogs.handler(logName=Troy.logName, mark='SERVER') # log使用方法:self.logObj.logHandler() # 实例化redis self.redisObj = ChangeRedis(self.config.get('redisConfig')) PrettyCode.prettyPrint('redis server 连接成功。') self.logObj.logHandler().info('redis server started successfully.') # rcc计时器线程 self.rccTimerWorker = ThreadPoolExecutor(max_workers=100)
def _performOrderCMD(self, order: str) -> None: """执行CMD命令函数 Args: order (str): CMD命令 """ self.lock.acquire() logMsg = 'Task started - {}'.format(order) self.logObj.logHandler().info(logMsg) worker = self.taskPool.submit( self.taskExecuteCMD, order, ) self.lock.release() result = Client.performOrderResult(worker) msg = '{} - 任务完成。'.format(order) PrettyCode.prettyPrint(msg)
def _ADH56(self, info: str, *args, **kwargs) -> None: # 系统信息处理 addr = args[0] self.logObj.logHandler().info('ADH56 function starts processing.') localInfo = ast.literal_eval(info[-1]) # 信息入库 systemInfoHashFields = '{}_{}'.format(addr, 'systemInfo') systemInfoIPListFields = '{}_{}'.format(addr, 'systemInfoIPV4') for key, value in localInfo.items(): # redis系统信息字段名 if isinstance(value, list): # IPV4 list for ip in value: self.redisObj.redisPointer().lpush(systemInfoIPListFields, ip) else: # another info self.redisObj.redisPointer().sadd(systemInfoHashFields, value) PrettyCode.prettyPrint('ADH56任务处理完成。') return 'd3'
def heartbeat(self) -> None: while 1: # 循环做异常判断检测用 if not self.tcpClientSocket: break # 普通心跳包 msg = self.makeInfoMsg() try: # 函数内层会进入循环 # 普通心跳包持续发送 self.sendMsg(msg) except Exception as e: # 心跳逻辑层异常 errorMsg = '[hb Error]意料之外的错误,将关闭本次TCP连接。错误信息:{} - {}'.format( e, e.__traceback__.tb_lineno) PrettyCode.prettyPrint(errorMsg, 'ERROR') break # 心跳进程结束 if self.tcpClientSocket: self.tcpClientSocket.close()
def TCPConnect(self) -> None: while 1: # tcp if self.tcpOnline.empty(): # 离线状态 tcpClientSocket = socket.socket() PrettyCode.prettyPrint('TCP对象创建成功。') # 重连次数 nOfRec = 0 # 连接服务器异常处理 while 1: recingMsg = '正在连接服务器中 {}'.format(nOfRec) PrettyCode.prettyPrint(recingMsg) try: hostIP = self.config.get('serverConfig').get('host') tcpClientSocket.connect((hostIP, 11451)) # 获取与套接字关联的本地协议地址 self.maternalIpInfo = ( tcpClientSocket.getsockname()[0], 6655) break except: nOfRec += 1 continue self.tcpOnline.put('ONLINE') # 连接成功,event为True self.event.set() PrettyCode.prettyPrint('服务器连接成功。') self.tcpClientSocket = tcpClientSocket time.sleep(10)
def taskExecuteCMD(self, task): """任务执行函数 Args: task (str): 任务执行命令 """ try: self.lock.acquire() msg = '正在执行 - {}'.format(task) PrettyCode.prettyPrint(msg) executor = subprocess.Popen(task, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) result = executor.stdout.read().decode('gbk') self.lock.release() return result except Exception as e: errorMsg = '{} - {}'.format(e, e.__traceback__.tb_lineno) self.logObj.logHandler().error(errorMsg) self.lock.release()
def _udpSenderSpecified(self, udpSocket: object, msg: str, specifyTheMole: list) -> None: """udp发包操作函数(指定客户端),只做发送操作。 Args: udpSocket (object): udp对象 msg (str): 需要发送的信息或任务ID。 specifyTheMole (list): 主机信息。 """ # 获取离线列表 offline = self.existsCheck(specifyTheMole) for mole in specifyTheMole: # 检查指定客户端是否存活 if mole not in offline: udpSocket.sendto(msg.encode('utf-8'), (mole, 6655)) printMsg = '{} - 下发完成 - 指定主机。'.format(mole) self.logObj.logHandler().info('{} - Delivery completed (specify host).'.format(mole)) PrettyCode.prettyPrint(printMsg) return True else: printMsg = '{} 下发失败 - 主机离线。'.format(mole) self.logObj.logHandler().info('{} - Delivery failed (specify host).'.format(mole)) PrettyCode.prettyPrint(printMsg, 'ERROR')
def __init__(self) -> None: socket.setdefaulttimeout(5) self.config = Client._loadingConfig() self.maternalIpInfo = None self.tcpClientSocket = None # 线程配置 self.event = threading.Event() self.lock = threading.Lock() self.tcpOnline = queue.Queue(1) # 任务池 self.taskPool = ThreadPoolExecutor(max_workers=10) # 报文信息(任务汇报) self.initializationTaskInfo = { 'flag': None, 'code': None, 'working': None, 'complete': [], 'oncall': [] } # 实例化日志 logName = 'ant_{}.log'.format(time.strftime('%S_%M_%H_%d_%m_%Y')) self.logObj = BasicLogs.handler(logName=logName) # 实例化redis self.redisObj = ChangeRedis(self.config.get('redisConfig')) PrettyCode.prettyPrint('redis server 连接成功。') # 启动前检查 self.checkBeforeStarting() # 日志开关 self.logEncrypt = True
def recvMsg(self) -> None: # udp self.udpClientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) while 1: if self.maternalIpInfo: # TCP创建完成后才能拿到地址 try: self.udpClientSocket.bind(self.maternalIpInfo) except Exception as e: # UDP连接异常排查 self.logObj.logHandler().error(e) self.checkBeforeStarting() time.sleep(5) self.udpClientSocket.bind(self.maternalIpInfo) break continue PrettyCode.prettyPrint('UDP对象创建成功。') # 永久等待信息下发 self.udpClientSocket.settimeout(None) while 1: try: data = self.udpClientSocket.recvfrom(1024) recvMsg = data[0].decode('utf-8') except Exception as e: # 数据意料之外的情况 self.logObj.logHandler().error(e) # 通知重发 self.sendMsg( self.makeInfoMsg(self._structureADH33Msg(3, recvMsg))) if recvMsg: msg = '数据已接收:{}\n'.format(recvMsg) logMsg = 'Data received - {}'.format(recvMsg) self.logObj.logHandler().info(logMsg) PrettyCode.prettyPrint(msg) # 正常应答 self.sendMsg( self.makeInfoMsg(self._structureADH33Msg(1, recvMsg))) # 判断信息类型 if recvMsg.startswith('AC'): # redis任务编码信息 tips = '开始执行任务,任务编号: {}'.format(msg) PrettyCode.prettyPrint(tips) # 执行任务 self._performOrderRedis(recvMsg) else: # cmd指令 self._performOrderCMD(recvMsg) recvMsg continue self.udpClientSocket.close()
def sendMsg(self, msg) -> None: """构建报头 Args: msg (str): 发送的信息。 Raises: e: 预料之外的错误。 """ while 1: msg = str(msg) try: if not self.tcpClientSocket: break # 加锁 self.lock.acquire() msgPack = struct.pack('i', len(msg)) self.tcpClientSocket.send(msgPack) self.tcpClientSocket.send(msg.encode('utf-8')) PrettyCode.prettyPrint('发送成功。') # 释放锁 self.lock.release() if 'keepAlive' not in msg: # 判断是普通心跳包还是其他信息 break # 发送间隔 time.sleep(5) except socket.timeout as timeoutE: # 释放锁 self.lock.release() PrettyCode.prettyPrint('发送超时,正在尝试重新发送。', 'ERROR') continue except Exception as e: # 释放锁 self.lock.release() errorMsg = '{}{}'.format(self._errorCheck(e), ',现在重启TCP。') PrettyCode.prettyPrint(errorMsg, 'ERROR') # 清空TCP客户端连接 self.tcpClientSocket = None raise e
def rccTimer(self, taskId: str) -> None: # 线程计时器 PrettyCode.prettyPrint('RCC定时器已启动 - {}'.format(taskId)) hookTime = time.time() field = '{}_response'.format(taskId) while 1: # 阻塞等待应答包,等待时间内不检查名单 nowTime = time.time() # 检查是否还存在应答名单 rtoCheck = nowTime - hookTime if rtoCheck >= self.rto: # 超时 responseTab = self.redisObj.redisPointer().smembers(field) if responseTab: # 还存在没有接收到报文的主机 -> 主动引发ADH33函数内的错误机制 for ip in responseTab: if isinstance(ip, bytes): PrettyCode.prettyPrint('{} - 任务超时,超时主机 - {}'.format(taskId, ip.decode('utf-8'))) else: PrettyCode.prettyPrint('{} - 任务超时,超时主机 - {}'.format(taskId, ip)) # 引发异常,引导重发 self._ADH33({ 'flag': 'ADH33', 'RCC': 0, 'taskId': taskId, 'answerTime': time.time(), }, (ip, )) time.sleep(1) # 重新进入检测 continue else: # 成功发送 break time.sleep(1)
def system_information_processing(self, *args, **kwargs): # 数据处理 self.logObj.logHandler().info('{} - Data submission returned successfully.'.format(self.addr)) PrettyCode.prettyPrint('数据处理信息:{} - {}'.format(self.addr, self.data))
def task_status_information_processing(self, *args, **kwargs): # 判断任务报文处理 self.logObj.logHandler().info('{} - Message processing returned successfully.'.format(self.addr)) PrettyCode.prettyPrint('任务报文信息:{} - {}'.format(self.addr, self.data))
def _performOrderRedis(self, taskId: str, standardEnd=True) -> None: """执行Redis命令函数 Args: taskId (str): 任务编号 standardEnd (bool, optional): 执行模式. Defaults to True. """ # 获取任务列表,从优先级最高到最低(zrange value 低的值优先级高) -> (任务,优先级) try: taskBook = self.redisObj.redisPointer().zrange(taskId, 0, -1, withscores=True, desc=True) if taskBook: # 正常获取 PrettyCode.prettyPrint('任务获取成功。') # 构造ADH27 -> 接收报文 initializationTaskInfo = { 'flag': 'ADH27', 'code': taskId, 'phase': 1, 'working': None, 'complete': [], # 添加任务至未完成列表并上传到redis 'oncall': [i[0] for i in taskBook], } # 发送讯息已经接收到任务,即将开始执行 taskInfo = self.makeInfoMsg(initializationTaskInfo) # print('接收报文', taskInfo) self.sendMsg(taskInfo) else: # 任务book为空,通知SERVER raise ValueError('taskbook is null!') except Exception as e: # 发送rcc为2的ADH33报文 errorMsg = '{} - {}'.format(e, e.__traceback__.tb_lineno) self.sendMsg( self.makeInfoMsg( self._structureADH33Msg(2, taskId, (errorMsg, )))) PrettyCode.prettyPrint('任务获取失败。') raise ValueError('任务获取失败。') # 开始执行任务 for task in taskBook: # 上锁 self.lock.acquire() msg = '开始执行 - {}'.format(task[0]) PrettyCode.prettyPrint(msg) # 向线程池提交任务 -> (任务,优先级) worker = self.taskPool.submit( self.taskExecuteCMD, task[0], ) self.lock.release() # 发送执行报文 initializationTaskInfo['phase'] = 2 initializationTaskInfo['working'] = task[0] taskInfo = self.makeInfoMsg(initializationTaskInfo) self.sendMsg(taskInfo) # print('执行报文', taskInfo) worker.add_done_callback(worker.result) result = Client.performOrderResult(worker) # 发送任务执行完成报文 initializationTaskInfo['phase'] = 3 taskStatusDict = self._taskReportMsgComplete( initializationTaskInfo, task[0]) taskInfo = self.makeInfoMsg(taskStatusDict) # print('完成报文', taskInfo) self.sendMsg(taskInfo) msg = '{} - 任务完成。'.format(task[0]) PrettyCode.prettyPrint(msg) # 任务执行间隔 time.sleep(5) return True
def _loadingConfig(): # 配置文件 return PrettyCode.loadingConfigJson(r'config.json')
def statusOfWork(self, addr: str, tasks: list, taskId: str, statusListField: str, statusHashField: str, *args, **kwargs) -> str: """报文任务字段信息处理模块 Args: addr (str): 客户端IP地址 tasks (list): 任务组 taskId (str): 任务ID statusListField (str): 状态(list字段) statusHashField (str): 状态(hash字段) complete (bool, optional): 完成/未完成任务模式. Defaults to True. Returns: str: 格式化后的list名字 """ # list: ip_status: task task task listField = '{}_{}_{}'.format(taskId, addr, statusListField) # 获取当前调用状态的储存的任务信息 complete/oncall allTasks = self.redisObj.redisPointer().lrange(listField, 0, -1) # 最后一个任务结束判断,redis oncall只剩最后一个,发来的报文 oncall 内已经全部执行完了 if len(allTasks) == 1 and not tasks: self.redisObj.redisPointer().lrem(listField, 1, tasks[0]) # 获取当前存入的新任务信息 if statusListField == 'complete': for nTask in tasks: '''目前传入的都是completeTask,即当前已完成的任务 complete: nTask -> 已完成的任务 如果当前任务在当前获取的allTasks中,即pss;如果不在则添加 oncall: nTask -> 已完成的任务 如果当前任务在获取的allTasks中,即删除; ''' if nTask not in allTasks: # redis已完成任务列表中没有此次传递完成任务列表的该项任务 getattr(self, '_statusOfWorkCompleted')(listField, nTask) printMsg = '{} 已添加完成列表。'.format(nTask) self.logObj.logHandler().info('ADDED: {}'.format(nTask)) PrettyCode.prettyPrint(printMsg) elif statusListField == 'oncall': for nTask in tasks: if nTask in allTasks: # 此次传递已完成任务列表的该项任务(nTask)在redis未完成任务列表中(该单项任务已经完成),删除notcomplete列表元素 getattr(self, '_statusOfWorkNotCompleted')(listField, nTask) printMsg = '{} 已删除未完成列表。'.format(nTask) self.logObj.logHandler().info('DELETED: {}'.format(nTask)) PrettyCode.prettyPrint(printMsg) if sorted(tasks) == sorted(allTasks): # 任务全部完成判断 -> 未完成任务列表为空,已完成任务列表等于所有任务列表 # 删除complete列表和hash保存项 completeListField = '{}_{}_{}'.format(taskId, addr, 'complete') self.redisObj.redisPointer().hdel('{}_complete'.format(taskId), addr) self.redisObj.redisPointer().delete(completeListField) # 删除working hash self.redisObj.redisPointer().hdel('{}_working'.format(taskId), addr) printMsg = '{} - All tasks have been completed'.format(addr) PrettyCode.prettyPrint(printMsg) self.logObj.logHandler().info(printMsg) return 1 # 为hash添加列表 if not self.redisObj.redisPointer().exists(statusHashField): self.redisObj.redisPointer().hset(statusHashField, addr, listField) return listField
def udpSendInstructions(self, udpScheduleArgs: object = None) -> None: """udp发包主函数 Args: udpScheduleArgs (object, optional): UDP调用模式参数,如果为None则进入控制台模式,如果为object则进入任务模式. Defaults to None. """ udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) PrettyCode.prettyPrint('UDP服务器启动成功。') PrettyCode.prettyPrint('udp服务器进入监听。') self.logObj.logHandler().info('UDP server started successfully.') while 1: if udpScheduleArgs: # specified (list, optional): 指定主机列表. Defaults to None. # dispatchCommands (dict, optional): 调度命令任务集. Defaults to None. # key (str, optional): 任务集名(编号). Defaults to None. specified, dispatchCommands, key = udpScheduleArgs.ipList(), udpScheduleArgs.disCommands(), udpScheduleArgs.key() assert isinstance(specified, list), '错误的类型数据,请传入list。' assert isinstance(dispatchCommands, dict), '错误的类型数据,请传入dict。' assert isinstance(key, str), '错误的类型数据,请传入str。' else: specified, dispatchCommands, key = 0, 0 ,0 msg = None # 获取所有存活主机信息 moles = [i for i in self.redisObj.redisPointer().smembers('exists')] if dispatchCommands and key: # 是否为调度模式下发判断 if self.redisObj.redisPointer().exists(key): # 判断该任务是否已经上传 PrettyCode.prettyPrint('此任务已经上传。', 'warning') self.logObj.logHandler().warning('upload repetitive tasks.') break # 上传任务 try: # msg == key msg = self._udpSendDispatchMode(key, dispatchCommands) except Exception as e: errorMsg = '{}{}'.format(e, e.__traceback__.tb_lineno) # 记录logs - 意料之外的错误 self.logObj.logHandler().error(errorMsg) continue else: # CMD控制台模式下发 try: # 获取用户输入值 PrettyCode.prettyPrint('进入CMD指令模式。') self.logObj.logHandler().info('Enter CMD.') msg = self._udpSendCmdMode() if msg == 'exit()': self.logObj.logHandler().info('Exit CMD.') # 退出控制台下发指令,关闭UDP服务器 `exit()` break except Exception as e: eMsg = (e.__traceback__.tb_lineno, e) self.logObj.logHandler().error(eMsg) continue # 下发信息 try: if not specified: # 下发所有存活客户端 # 上传应答表 self._responseForm(msg, moles) if not moles: # 如果没有存活主机 PrettyCode.prettyPrint('无存活主机接受信息。', 'warning') self.logObj.logHandler().warning('No online host.') continue PrettyCode.prettyPrint('执行下发所有存活客户端。') self._udpSenderAllSurvive(udpSocket, msg, moles) else: # 下发指定客户端 - specified is true assert isinstance(specified, list), '错误的类型数据,请传入list。' # 上传应答表 self._responseForm(key, specified) PrettyCode.prettyPrint('执行下发指定客户端。') self._udpSenderSpecified(udpSocket, msg, specified) PrettyCode.prettyPrint('执行下发指定客户端函数结束。退出udp服务器。') # rcc定时器记录开始 rccThread = self._rccControl(taskId=key) rccThread.start() continue except Exception as e: PrettyCode.prettyPrint('下发失败 - 意料之外的原因。', 'ERROR') print(e, e.__traceback__.tb_lineno) continue # udp函数关闭 PrettyCode.prettyPrint('udp下发函数关闭。或exit()生效。') self.logObj.logHandler().warning('UDP server close.')
def heartbeatMonitoring(self): # 数据接收调度函数 tcpSocket = socket.socket() localIP = self.config.get('localConfig').get('ip') tcpSocket.bind((localIP, 11451)) tcpSocket.listen(32) PrettyCode.prettyPrint('TCP服务器启动成功。') PrettyCode.prettyPrint('客户端心跳进入监听。') self.logObj.logHandler().info('TCP server started successfully.') while 1: conn, addr = tcpSocket.accept() # 子客户端超时设定 conn.settimeout(60) while 1: data = self._tcpRecverInstructions(conn, addr) # 信息为空就判断此客户端连接已经断开并删除redis存活列表的对应地址 if not data: # 当机器离线时的处理 msg = '{} - offline.'.format(addr[0]) # 离线记录日志 self.logObj.logHandler().warning(msg) # redis删除信息 self.redisObj.redisPointer().srem('exists', addr[0]) needDel = [] for i in self.config.get('offlineDelFields').get('system'): # 需要删除的字段名 field = '{}_{}'.format(addr[0], i) needDel.append(field) # 删除信息字段 for dels in needDel: self.redisObj.redisPointer().delete(dels) PrettyCode.prettyPrint('{} - 断开连接。'.format(addr[0])) break """当信息不为空时: 1. 打印(记录日志)存活信息 2. 查询redis存活列表是否存在此地址,如果存在就跳过,如果不存在(新主机)就添加 """ try: data = self.taskStatus(data = data.decode('utf-8'), addr = addr) except Exception as e: # 数据处理过程出错 errorMsg = '{} - {}'.format(e, e.__traceback__.tb_lineno) self.logObj.logHandler().error(errorMsg) PrettyCode.prettyPrint('数据异常,主动 {} 切断连接,开始等待其他连接。'.format(addr[0])) self.logObj.logHandler().warning('Data anomalies, {} actively cut off the connection.'.format(addr[0])) conn.close() break # 实例化复杂类 complexObj = ComplexCleanup(addr, data) dataDispatch = { 'd0': complexObj.heartbeat_packet_processing, 'd1': complexObj.task_status_information_processing, 'd2': complexObj.normal_response_packet_processing, 'd3': complexObj.system_information_processing, } if data not in dataDispatch.keys(): self.logObj.logHandler().error('Illegal data in `heartbeatMonitoring`, the data is {}'.format(data)) raise ValueError('Illegal data.') try: dataDispatch[data]() except Exception as e: # 异常情况 - 非异常数据错误(代码错误) errorMsg = ('{} - {}'.format(e, e.__traceback__.tb_lineno)) PrettyCode.prettyPrint(errorMsg) self.logObj.logHandler().error(errorMsg) self.logObj.logHandler().error('There are some unexpected situations, the error function: heartbeatMonitoring(self) error report specific location: determine that the heartbeat information has entered the else.') continue self.logObj.logHandler().warning('TCP server close.') PrettyCode.prettyPrint('TCP SERVER 退出。', 'warning')
def _ADH33(self, recvDataDict: dict, *args, **kwargs) -> bool: """应答包处理函数 Args: recvDataDict (dict): 应答数据。 Returns: bool: 应答处理状态 """ rcc = recvDataDict.get('RCC') taskId = recvDataDict.get('taskId', None) if args: addr = args[0][0] if rcc == 0 or rcc == 3: # 主动异常情况,需要对此设备重新下发指令,自动重发 logMsg = '{} -> Answer package exception, automatic retransmitting trigger, RCC={}'.format(addr, rcc) self.logObj.logHandler().error(logMsg) try: PrettyCode.prettyPrint('尝试重传: {} - {}'.format(taskId, *args[0])) self.logObj.logHandler().info('Try to retransmit -> {} - {}'.format(taskId, *args[0])) result = self._udpSenderSpecified( socket.socket(socket.AF_INET, socket.SOCK_DGRAM), taskId, list(args[0]), ) if result: PrettyCode.prettyPrint('重传成功: {} - {}'.format(taskId, *args[0])) self.logObj.logHandler().info('Retransmission success: {} - {}'.format(taskId, *args[0])) except Exception as e: printMsg = 'Retransmission failed: {} - {}'.format(e, e.__traceback__.tb_lineno) PrettyCode.prettyPrint(printMsg) self.logObj.logHandler().error(printMsg) return False elif rcc == 2: # 记录查到redis任务,手动处理 errorMsg = recvDataDict.get('errorMsg', None) msg = { 'RCC': 2, 'taskId': taskId, 'msg': 'The client does not recognize the tasks.', 'errorMsg': errorMsg, } # 上传redis field = '{}_unrecognized'.format(taskId) self.redisObj.redisPointer().sadd(field, addr) # 转成json给其他程序调用 result = json.dumps(msg) PrettyCode.prettyPrint('{}读取任务({})失败,已记录。'.format(addr, taskId)) self.logObj.logHandler().warning('{}Failed to read the task ({}), it has been recorded.'.format(addr, taskId)) return msg elif rcc == 1: # 正确应答,删除名单 field = '{}_response'.format(taskId) self.redisObj.redisPointer().srem(field, addr) printMsg = '{} - 接收完成 - 指定主机。'.format(addr) self.logObj.logHandler().info('{} - Received({})'.format(addr, taskId)) return 'd2' else: self.logObj.logHandler().error('Abnormal RCC value, in ADH33 func.') raise ValueError('异常的rcc值。')
def _ADH27(self, recvDataDict: dict, *args, **kwargs) -> str: """任务报文处理 Args: recvDataDict (Dict): 任务信息 addr (str): 客户端地址 Raises: e: 意料之外的错误 Returns: str: 报文码 """ # 获取数据 self.logObj.logHandler().info('ADH27 function starts processing.') addr = args[0][0] phase = recvDataDict.get('phase') if not recvDataDict.get('working') and recvDataDict.get('complete') and recvDataDict.get('oncall'): # 当前客户端没有任务 taskId, currentTask, completeTask, notCompleteTask = None, None, None, None # 可能是异常数据,提交了ADH27编号但没任务信息 self.logObj.logHandler().warning('It may be abnormal data. ADH27 number is submitted but no task information.') else: # 当前客户端有任务 try: taskId = recvDataDict.get('code') currentTask = recvDataDict.get('working') completeTask = recvDataDict.get('complete') notCompleteTask = recvDataDict.get('oncall') except Exception as e: errorMsg = '{} - {}'.format(e, e.__traceback__.tb_lineno) self.logObj.logHandler().error('There was an error assigning the task dictionary to the ADH27 function.') self.logObj.logHandler().error(errorMsg) if phase == 1: # 1阶段初始化未完成任务列表 listField = '{}_{}_oncall'.format(taskId, addr) for task in notCompleteTask: self.redisObj.redisPointer().lpush(listField, task) printMsg = '{} - 任务已经成功接收。'.format(addr) PrettyCode.prettyPrint(printMsg) else: statusFields = [] # HASH KEY. if taskId: for i in ['working', 'complete', 'oncall']: statusFields.append(self._makeFieldsName(taskId, i)) if phase == 2: """任务类型 currentTask(str) completeTask(list) notCompleteTask(list) """ # 任务状态检测 if currentTask: # 置换正在进行的任务 self.redisObj.redisPointer().hset(statusFields[0], addr, currentTask) printMsg = '当前任务已置换 {}'.format(currentTask) self.logObj.logHandler().info('Successful update: task in progress.') PrettyCode.prettyPrint(printMsg) if phase == 3: if completeTask: # 已完成的任务 hash -> list self.statusOfWork(addr, completeTask, taskId, 'complete', statusFields[1]) self.logObj.logHandler().info('Successful update: completed tasks.') if notCompleteTask: # 未完成的任务 hash -> list self.statusOfWork(addr, completeTask, taskId, 'oncall', statusFields[2]) self.logObj.logHandler().info('Successful update: unfinished tasks.') if not notCompleteTask and not currentTask: # 所有任务已完成 self.statusOfWork(addr, completeTask, taskId, 'oncall', statusFields[2]) self.logObj.logHandler().info('All tasks have been completed.') return 'd1'
def _loadingConfig(self): """读取配置文件 用户 -> list """ # 配置文件 self.config = PrettyCode.loadingConfigJson(r'.\config.json')