예제 #1
0
 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)
예제 #2
0
 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))
예제 #3
0
    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))
예제 #4
0
    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)
예제 #5
0
    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
예제 #6
0
    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)
예제 #7
0
    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)
예제 #8
0
 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'
예제 #9
0
    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()
예제 #10
0
    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)
예제 #11
0
    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()
예제 #12
0
    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')
예제 #13
0
    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
예제 #14
0
    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()
예제 #15
0
    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
예제 #16
0
    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)
예제 #17
0
 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))
예제 #18
0
 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))
예제 #19
0
    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
예제 #20
0
 def _loadingConfig():
     # 配置文件
     return PrettyCode.loadingConfigJson(r'config.json')
예제 #21
0
    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
예제 #22
0
    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.')
예제 #23
0
    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')
예제 #24
0
    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值。')
예제 #25
0
    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'
예제 #26
0
 def _loadingConfig(self):
     """读取配置文件
         用户 -> list
     """
     # 配置文件
     self.config = PrettyCode.loadingConfigJson(r'.\config.json')