def __login__handle__(self,json_data): task_type = json_data.get('task_type', '') handle_type = json_data.get('handle_type', '') user_type = json_data['user_info'].get('user_type','') json_response = { 'task_type': task_type, 'handle_type': 'response', 'user_info': '', } # 下线操作 if handle_type == 'offline': try: # 下线记录 self.__offline__() except Exception as ex: counter(server_log, 'CLIENT', 'LOGIN_HANDLE_OFFLINE_ERROR', ex) print_error('下线异常', self.hostname,ex) return # 上线和心跳操作 # 根据心跳时间更新,需要广播出去 elif handle_type == 'heart': self.time = json_data['user_info']['time'] # 客户端实体心跳信息,可以广播出去,也可以不广播 # 目前广播一下,保证状态同步正常,后续优化 if user_type != client.UI.value: __send_to_local__(json_data) else: pass
def __manager_msg__(self): while True: try: data = self.queue_in.get(True) #print_debug('接收到 发送到客户端的队列消息',data[:20]) if data[:20] == message.HEADER_HEART: try: json_data = message.msg_decode(data,message.HEADER_HEART) if not json_data: continue self.addr_client = tuple(json_data['user_info'].get('addr_client'))#(json_data['user_info'].get('addr_client'),json_data['user_info'].get('client_port')) print_success('客户端信息信息更新成功',self.hostname,self.addr_client) # 本地端口也发送给对端 self.__send_server_port__() except Exception as ex: print_warnning('客户端进程处理登录消息异常',ex) continue if not self.online: continue self.queue_to_client.put(data,True,1) except Exception as ex: print_error('客户端进程处理管理进程消息异常',ex) counter(server_log,'客户端进程处理管理进程消息异常', ex)
def __send_data_to_local__(data): result = False try: tcp = socket(AF_INET, SOCK_STREAM) tcp.settimeout(0.5) tcp.connect(('127.0.0.1', 61234)) tcp.send(data) if tcp.recv(512).decode('utf-8') == 'ACK': result = True except Exception as ex: counter(server_log, 'SEND_LOCAL', 'ERROR', ex) finally: return result
def get_user_info(clsbdh): jsonTemp = {} if clsbdh is None or clsbdh == '': counter(user_log, 'GET', 'USER', 'CLSBDH_NULL') return jsonTemp try: file_name = config_path + clsbdh + type_user if not os.path.exists(file_name): counter(user_log, 'GET', 'USER', 'CLSBDH_NOT_FOUND') return jsonTemp except Exception as ex: counter(user_log, 'GET', 'USER', 'FAIL_FOUND') return jsonTemp #用户配置相关信息 try: #前置默认值 with open(file_name, 'rb') as file_config: #加载配置文件 #user_str = unpack('i',file_config.read()) jsonTemp = pickle.load(file_config) file_config.close() return jsonTemp except Exception as ex: #user_conf['error'] = ex counter(user_log, 'GET', 'USER', 'ERROR', ex) return jsonTemp
def __send_type__(self,json_data,user_type): count = 0 for hostname_send in self.hosts.keys(): try: if user_type == self.hosts[hostname_send].get('user_type','') and \ self.hosts[hostname_send].get('status') == 'online': self.hosts[hostname_send]['queue_in'].put(json_data) count += 1 except Exception as ex: counter(server_log, 'SEND', 'ERROR', hostname_send, ex) continue else: counter(server_log,'SEND_TYPE','SUCCESS',count)
def __udp_send__(self): self.udp_send.settimeout(1) while True: try: # 透传给用户,10秒发送一次心跳 json_data = self.queue_to_client.get(True, 20) except Exception as ex: data = self.heart else: # JSON格式编码 try: data = dumps(json_data).encode() # 非JSON格式的直接转发 except: data = json_data #不在线状态下不发送 if not self.online: continue count = 0 while count < 3: count += 1 try: self.udp_send.sendto(data,self.addr_client) except Exception as ex: #print_warnning('发送消息到客户端失败,可能已经掉线',self.hostname,self.addr_client) #self.__send_server_port__() continue try: if self.udp_send.recv(512).decode() == 'ACK': break #有可能对方解析错误等原因 else: continue except Exception as ex: counter(server_log, 'SEND', 'ERROR_SEND_ACK', self.hostname, self.addr_client, ex) #self.__send_server_port__() #print_warnning('客户端实体发送进程处理异常', self.hostname, self.addr_client, ex) continue else: counter(server_log, 'SEND', 'SEND_FAIL', self.hostname, self.addr_client, ex)
def __offline__(self,hostname): if hostname in self.hosts.keys(): try: self.hosts[hostname]['queue_in'].close() except Exception as ex: pass try: self.hosts[hostname]['queue_out'].close() except Exception as ex: pass try: #直接杀死进程 self.hosts[hostname]['listen'].terminate() counter(server_log, 'OFFLINE', 'SUCCESS', hostname) except Exception as ex: counter(server_log,'OFFLINE','ERROR',hostname,ex)
def start(self): try: transfer = threading.Thread(target=self.__transfer__) transfer.setDaemon(True) transfer.start() transfer_data = threading.Thread(target=self.__transer_data__) transfer_data.setDaemon(True) transfer_data.start() login_handle = threading.Thread(target=self.__login_handle__) login_handle.setDaemon(True) login_handle.start() login_handle.join() transfer.join() except Exception as ex: print_error('客户端管理进程异常',ex) counter(server_log,'CLIENT_MANAGER_START_ERROR',ex)
def __udp_recv__(self): print_success('服务器端接收进程启动',self.hostname,self.server_recv_port) while True: try: # 验证码图片有300k吧 data,addr_client = self.udp_recv.recvfrom(300 * 1024) try: self.udp_recv.sendto('ACK'.encode(),addr_client) except Exception as ex: print_error('服务器接收进程响应ACK异常',self.hostname, ex) # 心跳消息,客户端软件重启等场景下,IP和端口可能需要更新 if data[:20] == message.HEADER_HEART: try: json_data = message.msg_decode(data,message.HEADER_HEART) if not json_data: continue #主要是更新IP self.addr_client = addr_client self.__send_server_port__() continue except Exception as ex: print_warnning('客户端进程处理登录消息异常',ex) continue # 如果IP变化,直接更新 elif addr_client[0] != self.addr_client[0]: self.addr_client = (addr_client[0],self.addr_client[1]) # 所有消息透传到处理进程 self.queue_from_client.put(data, True, 3) #服务器保持端口监听,不下线 except Exception as ex: counter(server_log, 'ERROR_RECV', self.hostname, ex) print_warnning('客户端接收进程异常',self.hostname,ex) time.sleep(2) continue
def __yzm_listen_query__(port,queue_yzm_fx): #外层循环用于发生异常之后,自动重启监听 #udp端口监听 addr_yzm = ('',port) try: udp = socket(AF_INET,SOCK_DGRAM) udp.bind(addr_yzm) #udp.listen(5) except Exception as ex: print_error('验证码缓存进程启动异常' + str(ex)) counter(yzmfx_log,'YZM_RECV','FAIL_LISTEN',port) return print_success('验证码缓存进程启动成功') while True: try: #udp接口监听,接收到消息立即放入队列缓存 while True: data,addr = udp.recvfrom(300*8*1024) json_data = { 'data':data, 'addr':addr, 'time':time.time(), } queue_yzm_fx.put(json_data,True,2) #counter(yzmfx_log, 'YZM_RECV', addr) except Exception as ex: counter(yzmfx_log,'YZM_RECV','ERROR',port,ex) print_warnning('验证码缓存进程运行异常,自动恢复' + str(ex)) #达到不到的分支 else: pass
def __send__(self, json_data, hostname=None): count = 0 if hostname in self.hosts.keys(): try: #离线客户端不发送数据 if self.hosts[hostname].get('status') != 'online': return self.hosts[hostname]['queue_in'].put(json_data) count += 1 except Exception as ex: counter(server_log,'SEND','ERROR',hostname,ex) elif hostname is None: for hostname_send in self.hosts.keys(): try: # 离线客户端不发送数据 if self.hosts[hostname_send].get('status') != 'online': continue self.hosts[hostname_send]['queue_in'].put(json_data) count += 1 except Exception as ex: counter(server_log, 'SEND', 'ERROR', hostname_send, ex) continue else: pass counter(server_log, 'SEND', 'SUCCESS', count)
def __msg_listen__(port, queue_from_net,queue_data): try: tcp = socket(AF_INET, SOCK_STREAM) addr = ('', port) tcp.bind(addr) tcp.listen(5) except Exception as ex: print_error('无连接开放监听进程启动异常',ex) counter(server_log,'LISTEN_MSG','ERROR',ex) print_success('无连接开放监听进程启动成功', port) while True: try: counter(server_log, 'LISTEN_MSG', 'RUNNING', port) tcp_pip, addr = tcp.accept() data = tcp_pip.recv(300 * 1024) #验证码,直接发送给客户端管理进程 if data[0:20] == b'0' * 20: queue_data.put(data,True,0.1) continue tcp_pip.send('ACK'.encode()) # json解析 json_data = loads(data.decode()) # 接收到的数据放入队列缓存 queue_from_net.put(json_data, True, 0.5) except Exception as ex: counter(server_log, 'LISTEN_MSG', 'ERROR', ex) print_error('无连接开放监听进程运行异常', ex) finally: pass
def __online__(self): self.online = True try: # 不是UI,实体均需要更新状态 # if self.user_type != client.UI.value: json_online = { 'task_type': 'host', 'handle_type': 'update', 'user_info': { 'hostname': self.hostname, 'status': 'online', }, } try: __send_to_local__(json_online) except Exception as ex: counter(server_log, 'CLIENT', 'OFFLINE_QUEUE_PUT_ERROR', self.hostname, ex) except Exception as ex: counter(server_log, 'CLIENT', 'OFFLINE_ERROR', 'ERROR', self.hostname, ex) print_warnning('客户端实体离线异常', self.hostname, ex)
def get_user_task(user_infor): user_infor['select_user'] = user_infor['clsbdh'] #启动任务 if user_infor['status'] == 'running': data = { 'task_type': 'select', 'handle_type': 'start', 'user_info': user_infor } counter(user_log, 'TASK', 'START') #停止任务 elif user_infor['status'] == 'idle': data = { 'task_type': 'select', 'handle_type': 'stop', 'user_info': { 'clsbdh': user_infor['clsbdh'], 'hostname': user_infor['hostname'], 'query_pc': user_infor['query_pc'], }, } counter(user_log, 'TASK', 'STOP', 'CONTROL') elif user_infor['status'] == 'success': task_request = 'stop' data = { 'task_type': 'select', 'handle_type': 'stop', 'user_info': { 'clsbdh': user_infor.get('clsbdh', ''), 'hostname': user_infor.get('hostname', ''), 'query_pc': user_infor.get('query_pc', ''), 'xzhm': user_infor.get('xzhm', ''), }, } counter(user_log, 'TASK', 'STOP', user_infor['xzhm']) else: return False return data
def delete_user_info(clsbdh): if clsbdh is None or clsbdh == '': counter(user_log, 'DELETE', 'USER', 'CLSBDH_NULL') return False try: file_name = config_path + clsbdh + type_user if not os.path.exists(file_name): counter(user_log, 'DELETE', 'USER', 'NOT_FOUND') return False os.remove(file_name) return False except Exception as ex: counter(user_log, 'DELETE', 'USER', 'ERROR', ex) return False
def __listen_handle__(queue_from_net, queue_to_net): #进程间通信 #查询和约号任务队列 query_queue = Queue(10) #查询和约号任务进程,界面窗口处理队列传递进来 query_task_process = Process(target=query_task, args=(query_queue, ), name='query') #查询任务监控队列直接启动 query_task_process.start() while True: try: data = queue_from_net.get(True) #采用队列方式 status, info = 200, 'ok' json_data = loads(data.decode()) json_data['user_info']['send_ip'] = '127.0.0.1' task_type = json_data.get('task_type', '') #查询任务及其他更新等等任务 if json_data['task_type'] == 'query' or \ json_data['task_type'] == 'select' or json_data['task_type'] == 'order' or \ json_data['task_type'] == 'yzm_response' or json_data['task_type'] == 'login' or \ json_data['task_type'] == 'yzm': #第二个参数等待阻断,第三个参数是超时时间,3s query_queue.put(json_data, True, 3) #约号相关的任务,传递给UI if json_data.get('task_type') == 'select': pass #任务记录 counter(listen_log_file, 'LISTEN_HANDLE', json_data['task_type'], json_data['handle_type']) else: counter(listen_log_file, 'LISTEN_HANDLE', 'ERROR', 'UNKNOW_TYPE', json_data['task_type']) except Exception as ex: counter(listen_log_file, 'LISTEN_HANDLE', 'ERROR', ex)
def __select_listen__(port,queue_transfer): udp = socket(AF_INET, SOCK_DGRAM) addr = ('', port) #61237 udp.bind(addr) print_success('约号用户登录监控线程启动成功', port) select_users = {} #10s超时,不能设置太长 while True: try: #阻塞模式 udp.settimeout(None) # 约号用户打洞地址 try: data, addr_src = udp.recvfrom(10 * 1024) json_data = loads(data.decode('utf-8')) except Exception as ex: print_error('解析约号用户登录消息异常') counter(server_log,'SELECT_LISTEN','LOAD_MSG_ERROR',ex) udp.settimeout(10) # select用户上线 if json_data.get('task_type') == 'login' and json_data.get('handle_type') == 'online': json_response = { 'task_type': 'login', 'handle_type': 'response', 'user_info': 'fail', } #clsbdh为空 clsbdh = json_data['user_info'].get('clsbdh', '') if clsbdh == '': json_response['user_info'] = 'null_clsbdh' udp.sendto(dumps(json_response).encode(), addr_src) continue # select地址用户信息保存 select_users[clsbdh] = addr_src #成功响应消息给SELECT用户 try: json_response['user_info'] = 'success' udp.sendto(dumps(json_response).encode(), addr_src) except Exception as ex: print_error('响应约号用户异常',ex) counter(server_log,'SELECT_LISTEN','RESPONSE_ERROR',ex) continue # 广播给所有PC,包括查询预约实体,以及UI实体 # 更新select用户的udp打洞地址信息 try: json_select_user = deepcopy(json_data) json_select_user['user_info']['select_addr'] = addr_src queue_transfer.put(json_select_user, True, 0.1) except Exception as ex: print_warnning('约号用户信息更新信息加入队列异常',ex) counter(server_log,'SELECT_LISTEN','QUEUE_PUT_ERROR',ex) print_infor('约号用户信息更新成功', clsbdh,addr_src) counter(server_log, 'SELECT_LISTEN', 'SUCCESS', clsbdh, addr_src) else: try: json_response['user_info'] = 'no_hostname_login_on_server_first' udp.sendto(dumps(json_response).encode(), addr_src) except Exception as ex: pass except Exception as ex: counter(server_log, 'SELECT_LISTEN', 'ERROR', ex) print_error('约号用户信息更新失败', ex)
def __yzm_fx__(queue_yzm_fx, index): while True: try: try: #本地加载dll,验证码识别模块初始化 lm_dll = ctypes.CDLL('./config/lm.dll') #加载进来,然后生成共享的函数 model_path = ctypes.c_char_p(b'./config/model_4chuang_0701') #path_bytes = ctypes.c_int(len('./config/model_4chuang_0701')) load_result = lm_dll.LoadModel(model_path, ctypes.c_int(100)) #本地引用获取验证码函数 cget_yzm = lm_dll.LM_REC_2 except Exception as ex: counter(listen_log_file, 'YZM_FX', 'LOAD', 'ERROR', ex, index) print_warnning('验证码控件加载异常,稍后重试' + str(ex)) time.sleep(5) continue print_success('验证码分析进程加载成功') counter(listen_log_file, 'YZM_FX', 'START', index) addr = None #tcp接口监听,接收到消息立即放入队列缓存 udp = socket(AF_INET, SOCK_DGRAM) #设置超时定时器 udp.settimeout(0.1) while True: #队列处理 time_start = time.time() json_data = queue_yzm_fx.get(True) try: #地址传入 addr = json_data.get('addr') if addr is None: counter(listen_log_file, 'YZM_FX', 'ERROR_ADDR', index) continue data = json_data.get('data') if data is None: counter(listen_log_file, 'YZM_FX', 'ERROR_DATA', index) continue result_buf = ctypes.c_char_p(b'') cget_yzm(ctypes.c_char_p(data), ctypes.c_int(len(data)), result_buf, ctypes.c_int(20)) #value是b'\xd1\xb8xr\xbc\xa4'格式,需要GBK解码 yzm_data = result_buf.value udp.sendto(yzm_data, addr) time_end = time.time() """counter(listen_log_file, 'YZM_SEND', yzm_data.decode('gbk'),addr, time_end - json_data.get('time',time_start), time_end - time_start)""" except Exception as ex: counter(listen_log_file, 'YZM_FX', 'SEND', 'ERROR', ex, addr, index) finally: pass #udp.shutdown(SHUT_RDWR) #udp.close() except Exception as ex: #udp.sendto(''.encode(), addr) #异常之后关闭UDP重新初始化 udp.shutdown(SHUT_RDWR) udp.close() counter(listen_log_file, 'YZM_FX', 'ERROR', ex, addr, index) print_error('验证码分析进程运行异常' + str(ex)) finally: lm_dll.DestroyModel()
def __token__(limit, period, port, max=100): addr_yzm = ('', port) tcp = socket(AF_INET, SOCK_STREAM) tcp.bind(addr_yzm) tcp.listen(5) query_user_limit = limit time_list = [] time_hphm_list = [] for index in range(0, max): time_hphm_list.append(0.0) time_query_list = [] for index in range(0, max): time_query_list.append(0.0) print_success('查询用户令牌进程启动成功', port, limit, max) #每秒钟最高的发送查号请求数,形成一个队列 while True: try: tcp_pip, addr = tcp.accept() data = tcp_pip.recv(5 * 1024).decode() #counter(listen_log_file, 'TOKEN', data) #获取hphm时token启动统计 if False and port == 62261: try: json_data = loads(data) index = int(json_data.get('index', -1)) hphm = float(json_data.get('hphm', 0)) plate = float(json_data.get('plate', 0)) #滤波计算 if index > 0 and index <= max: if hphm > 0: time_hphm_list[index - 1] = time_hphm_list[ index - 1] * 0.5 + hphm * 0.5 if plate > 0: time_query_list[index - 1] = time_query_list[ index - 1] * 0.5 + plate * 0.5 if hphm > 0 or plate > 0: sum = 0 count = 0 for i in time_hphm_list: if i > 0: sum += i count += 1 if count > 0: time_avg_hphm = float(sum / count) else: time_avg_hphm = 0 sum = 0 count = 0 for i in time_query_list: if i > 0: sum += i count += 1 if count > 0: time_avg_plate = float(sum / count) else: time_avg_plate = 0 counter(listen_log_file, 'TOKEN', '%2s' % index, '%7.3f' % time_avg_plate, '%7.3f' % time_avg_hphm, '%7.3f' % plate, '%7.3f' % hphm) except Exception as ex: counter(listen_log_file, 'ERROR', ex) pass cur_time = time.time() #最近少于限制的用户获取token if len(time_list) < query_user_limit: tcp_pip.send('ACK'.encode()) time_list.append(cur_time) #counter(listen_log_file,'QUERY_TOKEN','NEW',cur_time,data) #最近的用户已经间隔超过1s elif cur_time - min(time_list) > period: tcp_pip.send('ACK'.encode()) #counter(listen_log_file,'QUERY_TOKEN','UPDATE',cur_time,min(time_list),data) time_list.remove(min(time_list)) time_list.append(cur_time) else: #counter(listen_log_file,'QUERY_TOKEN','WAIT',cur_time,data) tcp_pip.send('NACK'.encode()) tcp_pip.close() except Exception as ex: print_warnning('查询用户令牌进程运行异常,' + str(ex)) continue
def __yzm_listen_select__(port, queue_to_net=None): #外层循环用于发生异常之后,自动重启监听 #tcp端口监听 addr_yzm = ('', port) try: tcp = socket(AF_INET, SOCK_STREAM) tcp.bind(addr_yzm) tcp.listen(5) except Exception as ex: counter(listen_log_file, 'YZM_LISTEN', 'FAIL_LISTEN', port) print_error('约号验证码启动异常' + str(ex)) return while True: try: try: #本地加载dll,验证码识别模块初始化 lm_dll = ctypes.CDLL("./config/lm.dll") #加载进来,然后生成共享的函数 model_path = ctypes.c_char_p(b'./config/model_4chuang_0701') #path_bytes = ctypes.c_int(len('./config/model_4chuang_0701')) load_result = lm_dll.LoadModel(model_path, ctypes.c_int(100)) #本地引用获取验证码函数 cget_yzm = lm_dll.LM_REC_2 except Exception as ex: counter(listen_log_file, 'YZM_LISTEN_SELECT', 'LOAD', 'ERROR', ex) print_warnning('验证码控件加载异常,稍后重试恢复' + str(ex)) time.sleep(5) continue counter(listen_log_file, 'YZM_LISTEN_SELECT', 'START', port) print_success('约号验证码启动正常') #tcp接口监听,接收到消息立即放入队列缓存 while True: tcp_pip, addr = tcp.accept() time_start = time.time() #验证码二进制字符串,不解码 data = tcp_pip.recv(300 * 8 * 1024) #.decode('utf-8') result_buf = ctypes.c_char_p(b'') buf_bytes = ctypes.c_int(20) #需要吐给窗口界面处理,select用户的验证码,需要解析出clsbdh和码1或者码2属性 #file_flag = file_in['data'][0:17] + file_in['data'][17:18] + '$' #前面17位是车架号,紧跟1位是码1还是码2,后面data是图片数据 #clsbdh = data[0:17] #yzm_type = data[17:18] #data = data[19:] #counter(listen_log_file,'YZM_LISTEN','SELECT',data[0:17].decode(),data[17:18].decode()) cget_yzm(ctypes.c_char_p(data[18:]), ctypes.c_int(len(data)), result_buf, buf_bytes) time_end = time.time() #yzm = unicode( result_buf.value,'gbk').decode('utf-8') #二进制结果 #yzm =result_buf.value yzm_data = result_buf.value #counter(listen_log_file, 'YZM_LISTEN', 'SELECT', data[0:17].decode(), data[17:18].decode(),yzm_data,time_end - time_start) tcp_pip.send(yzm_data) tcp_pip.close() json_temp = { 'task_type': 'yzm', 'handle_type': 'refresh', 'user_info': { 'yzm': result_buf.value, #'data':data.decode('utf-8'), } } #20个0标识头 yzm_head = b'0' * 20 id_fmt = '!20s' #body_head = pack(id_fmt,dumps(json_temp).encode()) yzm_value = pack(id_fmt, result_buf.value) queue_to_net.put(yzm_head + yzm_value + data, True, 2) except Exception as ex: counter(listen_log_file, 'YZM_LISTEN', 'ERROR', port, ex) print_warnning('验证码缓存进程运行异常,自动恢复' + str(ex)) finally: lm_dll.DestroyModel()
configInfo = {} try: #主程序端口contro_port #验证码端口yzm_fx_port #服务器域名或者IPserver_host with open('./config/config.ini', 'r') as config_file: for line in config_file: if '=' in line: config_key = line.split('=')[0].strip() config_value = line.split('=')[1].strip() if config_key != '' and config_value != '': configInfo[config_key] = config_value except Exception as ex: counter(listen_log_file, 'MAIN', 'CONFIG', 'ERROR', ex) print_error('加载配置文件异常', ex) #初始化IP while True: if configInfo.get('net_flag') != 'true' and configInfo.get( 'net_flag') != 'True': break result = rasdial(configInfo=configInfo) # 如果换IP失败,等待5s重新尝试更换 if not result: print_success('宽带连接初始化失败,2秒后重试') time.sleep(2) continue
def __msg_handle__(queue_from_net,queue_transfer): # 启动的时候加载文件列表 print_success('公共消息处理进程启动成功') counter(server_log, 'MSG_MANAGER', 'MSG_HANDLE', 'SUCCESS') while True: try: json_data = queue_from_net.get(True) task_type = json_data.get('task_type') handle_type = json_data.get('handle_type') # 如果选好成功,刷新 if task_type == 'order': # 号牌选择成功 if handle_type == 'response': # 约号成功消息处理 if json_data['user_info']['result'] == 'success': config_temp = { 'clsbdh': json_data['user_info']['clsbdh'], 'xzhm': json_data['user_info']['xzhm'], # 'yxzt':'1', 'status': 'success', } # 其他场景未定义 else: continue counter(server_log, 'XZHM', json_data['user_info']['clsbdh'], json_data['user_info']['xzhm']) print_success('约号成功', '用户', json_data['user_info']['clsbdh'], '号码', json_data['user_info']['xzhm']) # 保存配置,发送失败怎么办? result = save_user_info(config_temp, handle='success') # 直接广播停止的消息 json_offline = { 'task_type': 'select', 'handle_type': 'stop', 'user_info': { 'clsbdh': json_data['user_info']['clsbdh'], 'xzhm':json_data['user_info']['xzhm'] } } #通知到所有客户端 queue_transfer.put(json_offline,True,0.1) # 记录已经查询到的号牌信息并存档 elif json_data['handle_type'] == 'report': # 分割xzhm xzhm = json_data['user_info']['xzhm'] xzhm_list = [] xzhm_item = xzhm[:5] while xzhm_item != '': if not xzhm_item in xzhm_list: xzhm_list.append(xzhm_item) xzhm = xzhm[5:] xzhm_item = xzhm[:5] # 记录到当天的结果里面,按照日期归档 plate_name = time.strftime("%Y-%m-%d", time.localtime()) # 持久化存档,以车牌号的名称命名,文件操作太频繁了 with open(plate_path + plate_name, 'a') as fileTemp: fileTemp.write(',' + ','.join(xzhm_list)) fileTemp.close() else: pass # query或者select用户类消息直接转发给hostname电脑或者广播 # 这个是 elif task_type == 'query' or task_type == 'select': try: json_task = deepcopy(json_data) queue_transfer.put(json_task,True,0.1) except Exception as ex: counter(server_log,'MSG_HANDLE','QUERY_OR_SELECT_ERROR',ex) print_error('公共消息进程处理实体任务异常',ex) #日志消息 elif task_type == 'log': if handle_type == 'report': json_log = deepcopy(json_data) json_log['user_type'] = client.UI.value queue_transfer.put(json_log,True,0.1) else: print_error('无法识别的日志类型', task_type, handle_type) else: try: queue_transfer.put(json_data,True,0.1) except Exception as ex: print_error('公共消息进程到客户端管理进程转发异常',ex) except Exception as ex: print_error('开放接口消息处理异常', ex) counter(server_log, 'MSG_HANDLE', 'ERROR', ex)
def __transfer__(self): while True: try: json_data = self.queue_transfer.get(True) except Exception as ex: print_error('中转进程获取消息失败') counter(server_log,'TRANSFER','GET_ERROR',ex) else: print_infor('中转进程有消息需要处理') try: task_type = json_data.get('task_type') handle_type = json_data.get('handle_type') user_type = json_data.get('user_type') hostname = json_data.get('hostname') #host在线状态,唯一需要客户端管理模块处理的消息 if task_type == 'host': if handle_type == 'query': print_debug('host查询消息',hostname) json_send = self.__get_hosts__() self.__send__(dumps(json_send).encode(),hostname) #更新本地保存信息,一般都是只有一个客户端 elif handle_type == 'update': try: host_data = json_data.get('user_info') if 'hostname' in host_data: hostname_temp = host_data['hostname'] if 'status' in host_data: self.hosts[hostname_temp]['status'] = host_data['status'] if 'cxtj' in host_data: self.hosts[hostname_temp]['cxtj'] = host_data['cxtj'] if self.hosts[hostname_temp].get('user_type') != client.UI.value: # 广播给UI self.__send_type__(dumps(json_data).encode(), client.UI.value) except Exception as ex: print_warnning('服务器更新客户端信息存在问题') pass #按照用户类型广播 elif 'user_type' in json_data: self.__send_type__(dumps(json_data).encode(), user_type) #按照客户端名称单播 elif 'hostname' in json_data: self.__send__(dumps(json_data).encode(),json_data['hostname']) #广播给所有用户 else: self.__send__(dumps(json_data).encode()) except Exception as ex: counter(server_log,'TRANSFER','SEND_ERROR',ex) print_error('服务器中转消息失败')
def __login_handle__(self): try: udp = socket(AF_INET, SOCK_DGRAM) print_success('服务器客户端管理进程启动', self.port) udp.bind(('', self.port)) except Exception as ex: print_error('服务器客户端管理进程启动异常,请重启',self.port) return while True: try: data, addr_client = udp.recvfrom(5*1024) udp.sendto('ACK'.encode(),addr_client) except Exception as ex: counter(server_log,'CLIENT_MANAGER', 'RECV_DATA', 'ERROR', ex) try: json_data = message.msg_decode(data, message.HEADER_HEART) if not json_data: counter(server_log, 'CLIENT_MANAGER', 'LOAD_DATA', 'FAIL', data[:20]) print_warnning('服务器客户端管理进程接收到异常消息',data[0:20]) continue hostname = json_data['user_info'].get('hostname', '') user_type = json_data['user_info'].get('user_type', '') except Exception as ex: counter(server_log, 'CLIENT_MANAGER', 'LOAD_DATA', 'ERROR', ex) continue #实体已经创立 if hostname in self.hosts: try: #IP添加进去 json_data['user_info']['addr_client'] = addr_client self.hosts[hostname]['queue_in'].put(message.msg_encode(json_data,message.HEADER_HEART)) print_infor('客户端更新', hostname, user_type, addr_client ) except Exception as ex: print_error('客户端更新异常',hostname,ex) counter(server_log, 'CLIENT_MANAGER', 'LOGIN_REFRESH_ERROR', hostname, ex) #新建实体 else: # 保存客户端登录信息 self.hosts[hostname] = { 'hostname': hostname, 'user_type': user_type, 'queue_in':Queue(100), #输入队列 'queue_out':Queue(100), #输出队列 'status':'offline', 'cxtj':'' } try: self.hosts[hostname]['listen'] = Process(target=__client_start__, args=(self.hosts[hostname]['queue_in'],self.hosts[hostname]['queue_out'], hostname,user_type,addr_client,)) self.hosts[hostname]['listen'].start() print_infor('客户端登录',hostname,user_type,addr_client) #counter(server_log, 'CLIENT_MANAGER', 'LOGIN', hostname,user_type,addr_client) except Exception as ex: print_infor('客户端登录异常', hostname, ex) counter(server_log, 'CLIENT_MANAGER', 'LOGIN', hostname, ex) if user_type != client.UI.value: try: # 广播给所有的UI更新状态 self.__send_type__(message.msg_encode(json_data, message.HEADER_NULL), client.UI.value) except Exception as ex: print_warnning('客户端登录状态通知到UI界面发生异常,可能会影响任务管理',ex)
def __listen_client__(self): while True: try: data_from_net = self.queue_from_client.get(True) # 验证码图片,不进行json解码 if data_from_net[0:20] == b'0' * 20: self.__yzm_transfer__(data_from_net) continue else: try: json_data = loads(data_from_net.decode()) except Exception as ex: print_error('解析非验证码数据异常', self.hostname, data_from_net[:20] ,ex) continue task_type = json_data.get('task_type', '') handle_type = json_data.get('handle_type', '') # user_type分三种,一种是client (client_query和client_select是只支持查询或者约号的客户端),一种是ui,一种是服务器本地创建的任务 print_infor('客户端任务请求', task_type, handle_type) if 'user_info' in json_data.keys(): if 'user_type' in json_data['user_info'].keys(): user_type = json_data['user_info'].get('user_type') else: user_type = 'local' else: user_type = 'local' except Exception as ex: counter(server_log, '__listen_client__: error', ex) print_error('客户端消息解析异常', self.hostname, ex) continue try: # 客户端实体在线信息处理 if task_type == 'login': self.__login__handle__(json_data) # 约号用户操作,主要是界面发送过来的任务请求 elif task_type == 'user': self.__user_handle__(json_data) # 验证码,主要是select用户的验证码远程监控对错 elif task_type == 'yzm': self.__yzm_handle__(json_data) #如果是UI请求,一般是查询host列表 elif task_type == 'host': json_data['hostname'] = self.hostname __send_to_local__(json_data) # 触发select用户重新登录等信息 elif task_type == 'select': #self.__send_select__(json_data) __send_to_local__(json_data) else: print_warnning('未知的任务类型', task_type, handle_type) except Exception as ex: counter(server_log, 'ClIENT','LISTEN_CLIENT_ERROR',self.hostname, ex) print_error('客户端实体监听进程异常', self.hostname, ex)
def __user_handle__(self,json_data): task_type = json_data.get('task_type', '') handle_type = json_data.get('handle_type', '') user_type = json_data['user_info'].get('user_type', '') json_response = { 'task_type': task_type, 'handle_type': 'response', 'user_info': '', } # 查询用户列表 if handle_type == 'all' or handle_type == 'running' or handle_type == 'idle' or \ handle_type == 'success': users = get_user_list(handle_type) json_response['handle_type'] = 'list' json_response['user_info'] = users self.queue_to_client.put(json_response,True,1) counter(server_log, 'CLIENT', 'GET', 'USERS', handle_type) print_infor('UI请求查询用户信息', handle_type) # 删除用户行为,广播给所有客户端 elif handle_type == 'delete': result = save_user_info(json_data.get('user_info'), handle='delete') json_response['handle_type'] = 'delete' json_response['user_info'] = { 'clsbdh': json_data['user_info'].get('clsbdh'), } self.queue_to_client.put(json_response, True, 1) counter(server_log, 'CLIENT', task_type, handle_type, 'DELETE', json_data['user_info'].get('clsbdh')) print_infor('UI请求删除用户信息', json_data['user_info'].get('clsbdh')) # 单个用户信息更新 elif handle_type == 'update': result = save_user_info(json_data.get('user_info'), handle='update') if not result: pass json_response['handle_type'] = 'update' json_response['user_info'] = get_user_info(json_data['user_info'].get('clsbdh')) # 约号用户信息更新,需要广播给所有UI json_response['user_type'] = client.UI.value __send_to_local__(json_response) counter(server_log, 'CLIENT', task_type, handle_type, 'UPDATE', json_data['user_info'].get('clsbdh')) print_infor('UI请求更新用户信息', json_data['user_info'].get('clsbdh')) # 启动或者停止任务 elif handle_type == 'start' or handle_type == 'stop': counter(server_log, 'CLIENT', 'USER', handle_type, json_data['user_info'].get('clsbdh')) print_infor('UI请求改变任务状态', json_data['user_info'].get('clsbdh'), handle_type) json_data['user_info']['status'] = 'running' if handle_type == 'start': status = 'running' elif handle_type == 'stop': status = 'idle' else: counter(server_log, 'UILISTEN', 'FAIL_TYPE', task_type, handle_type, json_data['user_info'].get('clsbdh')) print_warnning('UI任务操作的类型不对', json_data['user_info'].get('clsbdh'), handle_type) status = '' if status != '': json_handle = { 'clsbdh': json_data['user_info']['clsbdh'], 'status': status, } result = save_user_info(json_handle, handle=handle_type) if result: json_response['handle_type'] = 'update' json_response['user_info'] = { 'clsbdh': json_data['user_info']['clsbdh'], 'status': status, } #发送给实体 result['user_type'] = client.CLIENT.value __send_to_local__(result) #发送给UI json_response['user_type'] = client.UI.value __send_to_local__(json_response) else: pass
def save_user_info(json_data, handle='update'): if json_data is None: print_error('更新用户信息,但是数据为空') return False try: clsbdh = json_data.get('clsbdh') if clsbdh == '' or clsbdh is None: counter(user_log, 'SAVE', 'FAIL', 'NULL_CLSBDH') print_error('更新用户信息,但是没有有效的clsbdh') return False user_infor = get_user_info(clsbdh) if handle == 'delete': if user_infor.get('status') != 'idle': counter(user_log, 'SAVE', 'DELETE', 'FAIL', clsbdh, 'NOT_IDLE', user_infor.get('status')) print_error('删除用户信息,但是用户不空闲') return False return delete_user_info(clsbdh) #更新用户 if user_infor: for key, value in json_data.items(): #如果是xzhm不为空,不需要更新,否则更新 if key == 'xzhm' and user_infor.get('xzhm', '') != '': continue user_infor[key] = value #新建用户 else: user_infor = json_data #用户任务属性固定为select user_infor['task_type'] = 'select' if user_infor.get('xzhm', '') != '': user_infor['status'] = 'success' #持久化存储 file_name = config_path + clsbdh + type_user with open(file_name, 'wb') as file_config: pickle.dump(user_infor, file_config) file_config.close() except Exception as ex: counter(user_log, 'SAVE', 'CONFIG', 'ERROR', ex) print_error('更新用户信息异常', ex) return False try: counter(user_log, 'SAVE', 'SUCCESS', clsbdh) #触发任务更新,已经约好的用户不能重复操作 if handle == 'start' or handle == 'stop': return get_user_task(user_infor) #约好成功的回执,status状态也为sucess elif handle == 'success': counter(user_log, 'SAVE', 'XZHM', user_infor.get('xzhm', '')) return get_user_task(user_infor) else: pass return False except Exception as ex: counter(user_log, 'SAVE', 'TASK', 'ERROR', ex) return False
configInfo = {} try: # 主程序端口contro_port # 验证码端口yzm_fx_port # 服务器域名或者IPserver_host with open('./config/config.ini', 'r') as config_file: for line in config_file: if '=' in line: config_key = line.split('=')[0].strip() config_value = line.split('=')[1].strip() if config_key != '' and config_value != '': configInfo[config_key] = config_value except Exception as ex: counter(server_log, 'MAIN', 'CONFIG', 'ERROR', ex) print_error('加载配置文件异常', ex) #管理中心建立进程 task_list = [] queue_from_net = Queue(1000) queue_transfer = Queue(1000) queue_data = Queue(50) # query验证码分析队列 queue_yzm_fx = Queue(100) # 中控监听 task_list.append(Process(target=__yzm_listen_query__,