def run(self): """线程主函数 循环运行,接受新的客户端的连接。 """ log.info('station server thread: start, port: %d' % self.port) try: server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if os.name != 'nt': server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('0.0.0.0', self.port)) server.listen(1) server.settimeout(3) # timeout: 3s while self.running: try: conn, address = server.accept() conn.settimeout(3) log.debug('new station connection from: %s' % str(address)) self.got_client(conn, str(address)) except socket.timeout: pass self.check_new_connections() # clean up server.close() self.disconnect() log.info('station server thread: bye') except Exception as e: log.error('station server thread error: %s' % e) self.running = False self.disconnect()
def start_rtk_threads(self, entries): """停止某 rtk 线程,不等待 之后需要调用 wait_for_thread Args: entries (dict[str, dict]): 各组 rtk 转发配置 """ if isinstance(entries, dict): # start threads from config for name, config in entries.items(): # start one thread try: if name in self.rtk_threads.keys(): # 如果已有 rtk_group = self.rtk_threads[name] # 判断配置是否发生改变,如果不变并且在运行,就跳过 if rtk_group.is_alive() and rtk_group.config == config: continue self.stop_and_wait_for_thread(name) rtk_group = RtkGroup(name, self.thread_count, config, self.status_queue) self.thread_count += 1 rtk_group.start() self.rtk_threads[name] = rtk_group except Exception as e: log.error('main: failed to start thread %s: %s' % (name, e)) # stop threads not in config for name in self.rtk_threads.keys(): if name not in entries.keys(): self.stop_and_wait_for_thread(name) del self.rtk_threads[name]
def start_rtk_threads(self, entries): """根据配置文件启动 rtk 线程 Args: entries (dict[str, Entry]): 各组 rtk 转发配置 """ if isinstance(entries, dict): # stop threads not in config for name in sorted(self.rtk_threads.keys()): if name not in entries.keys(): self.stop_and_wait_for_thread(name) # start threads from config for name, config in entries.items(): if isinstance(config, Entry): # start one thread try: if name in self.rtk_threads.keys(): # 如果已有 rtk_group = self.rtk_threads[name] # 判断配置是否发生改变,如果不变并且在运行,就跳过 if rtk_group.is_alive( ) and rtk_group.config == config: continue self.stop_and_wait_for_thread(name) rtk_group = RtkGroup(name, self.thread_count, config, self.status_queue) self.thread_count += 1 rtk_group.start() self.rtk_threads[name] = rtk_group except Exception as e: log.error('main: failed to start thread %s: %s' % (name, e))
def run(self): """线程主函数 循环运行,接受到控制端口的 socket 连接(唯一),接收命令。 """ if self.port is None: return log.info('control thread: start, port: %d' % self.port) try: # 开始监听 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('0.0.0.0', self.port)) server.listen(1) server.settimeout(3) # timeout: 3s # 循环运行,监听端口,接收命令 while self.running: self.accept_client(server) self.receive_command() self.resolve_command() self.send_message() server.close() self.disconnect_client() log.info('control thread: bye') except Exception as e: log.error('control thread error: %s' % e) self.running = False
def run(self): """线程主函数 循环运行,接受新的客户端的连接。 """ log.info('server thread: start, port: %d' % self.port) try: server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if os.name != 'nt': server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('0.0.0.0', self.port)) server.listen(100) # 并发 server.settimeout(1) # timeout: 1s while self.running: # 接受连接 try: conn, address = server.accept() conn.settimeout(3) self.dispatcher.add_client(conn, address) log.debug('new client from: %s' % str(address)) except socket.timeout: pass # 分发数据 self.dispatcher.dispatch() server.close() self.dispatcher.close_all_clients() log.info('server thread: bye') except Exception as e: log.error('server thread error: %s' % e) self.running = False
def load_config(self): """载入配置文件 先读入 conf/config.json 中的配置,再读入 conf/ 中其他 json 文件里的 entry """ config_dir = os.path.join(sys.path[0], 'conf') configs = {} # main config config_file_name = os.path.join(config_dir, 'config.json') try: with open(config_file_name) as config_fp: configs = json.load(config_fp) except Exception as e: log.error('main: failed to load config from conf/config.json: %s' % e) if 'entry' not in configs.keys(): configs['entry'] = {} # other entries for dir_path, dir_names, file_names in os.walk(config_dir): for file_name in file_names: if file_name != 'config.json' and file_name.endswith('.json'): # load sub config config_file_name = os.path.join(config_dir, file_name) try: with open(config_file_name) as config_fp: sub_configs = json.load(config_fp) # insert into main config for name, config in sorted(sub_configs['entry'].items()): if name not in configs['entry'].keys(): configs['entry'][name] = config except Exception as e: log.error('main: failed to load config from conf/%s: %s' % (file_name, e)) return configs
def disconnect(self): """断开连接""" try: self.client_socket.close() except socket.error: pass except Exception as e: log.error('station connection thread exception when close: %s' % e)
def disconnect(self): """断开连接""" try: self.client_socket.close() except socket.error: pass except Exception as e: log.error('sender thread %d exception when close: %s' % (self.sender_id, e))
def push_back(self, data): """加入新收到的数据 (list) Args: data (list): 新收到的数据 """ try: self.data.extend(data) except Exception as e: log.error('checker error when add: %s' % e)
def push_back(self, data): """加入新收到的数据 (list) Args: data (list): 新收到的数据 """ try: self.data.extend(data) except Exception as e: log.error("checker error when add: %s" % e)
def stop_thread(self, name, thread_to_stop): """结束指定线程 Args: name (str): 要结束的线程名,名字仅用于 log thread_to_stop (threading.Thread): 要结束的线程 """ try: thread_to_stop.running = False thread_to_stop.join() except Exception as e: log.error('rtk thread: failed to stop thread %s: %s' % (name, e))
def receive_command(self): """从控制端口接收数据 并在发生异常时进行处理。 """ if self.client is not None: try: self.receive_data() except socket.timeout: # 允许超时 pass except Exception as e: log.error('control client error: %s' % e) self.disconnect_client()
def run(self): """线程主函数 循环运行,接收来自客户端的数据并丢弃,向客户端发送 data_queue 中的数据包。 当 data_queue 过长时,丢弃旧的数据包。 """ log.info('station connection thread: start, %s' % self.address) self.update_status_cb(RtkStatus.S_CONNECTED) try: self.send_and_receive_data() except Exception as e: log.error('station connection thread error: %s' % e) self.update_status_cb(RtkStatus.S_DISCONNECTED) log.info('station connection thread: bye')
def run(self): """线程主函数 启动定时器,用于检查心跳超时 循环运行,接受新的客户端的连接。 """ log.info("http thread: start, port: %d" % self.port) try: self.server = ThreadingHTTPServer(("", self.port), RequestHandler) self.server.serve_forever() except Exception as e: log.error("http thread error: %s" % e) time.sleep(0.5) log.info("http thread: bye")
def stop_thread(self, name): """停止某 rtk 线程,不等待 之后需要调用 wait_for_thread Args: name (str): rtk 线程名 """ try: if name in self.rtk_threads.keys(): rtk_thread = self.rtk_threads[name] if isinstance(rtk_thread, RtkGroup): rtk_thread.stop() log.info('main: require stop thread %d %s.' % (rtk_thread.thread_id, name)) except Exception as e: log.error('main: failed to stop thread %s: %s' % (name, e))
def run(self): """线程主函数 循环运行,接收来自客户端的数据并丢弃,向客户端发送 data_queue 中的数据包。 当 data_queue 过长时,丢弃旧的数据包。 """ log.info('station connection thread: start, %s' % self.address) self.update_status_cb(RtkStatus.S_CONNECTED) try: self.send_and_receive_data() except Exception as e: log.error('station connection thread error: %s' % e) self.update_status_cb(RtkStatus.S_DISCONNECTED) self.running = False log.info('station connection thread: bye')
def run(self): """线程主函数 启动定时器,用于检查心跳超时 循环运行,接受新的客户端的连接。 """ log.info('http thread: start, port: %d' % self.port) try: self.server = ThreadingHTTPServer(('', self.port), RequestHandler) self.server.serve_forever() except Exception as e: log.error('http thread error: %s' % e) time.sleep(0.5) log.info('http thread: bye')
def get_parsed_data(self): """解析数据 Returns: return (bytes): 解析了的完整报文 """ # 拷贝 self.rtcm_checker.push_back(self.data) self.data.clear() try: # 解析 return self.rtcm_checker.get_parsed_data() except Exception as e: log.error('checker error when parse msg: %s' % e) return None
def wait_for_thread(self, name): """等待某 rtk 线程完全退出 在 stop_thread 之后调用 Args: name (str): rtk 线程名 """ try: if name in self.rtk_threads.keys(): rtk_thread = self.rtk_threads[name] if isinstance(rtk_thread, RtkGroup): # wait rtk_thread.join() log.info('main: thread %d %s has stopped.' % (rtk_thread.thread_id, name)) # remove del self.rtk_threads[name] except Exception as e: log.error('main: error when wait for thread %s: %s' % (name, e))
def run(self): """线程主函数 循环运行,建立连接、接收数据,并在连接出错时重连。 """ log.info('station client thread: start') while self.running: try: # 建立连接 conn = self.connect() log.info('station client thread: connected') # 开启数据接收线程 self.run_receive_data_thread(conn) except Exception as e: log.error('station client thread error: %s' % e) time.sleep(3) # disconnect self.disconnect() log.info('station client thread: bye')
def disconnect_client(self): """断开连接并清理""" if self.client is not None: # say goodbye try: self.client.sendall(b'bye') except: pass # close socket try: self.client.close() except socket.error: pass except Exception as e: log.error('control client exception when close: %s' % e) # clean up self.client = None self.buffer.clear() self.is_in_command = False
def pop_front(self, len_to_remove): """从 data 开头移除数据 (bytes) Args: len_to_remove (int): 要删除的数据长度 Returns: ret_data (list): 被删除的数据 """ ret_data = None try: if len_to_remove > 0: if len_to_remove < len(self.data): ret_data = self.data[:len_to_remove] self.data = self.data[len_to_remove:] else: ret_data = self.data[:] self.data.clear() except Exception as e: log.error('checker error when remove data: %s' % e) return ret_data
def pop_front(self, len_to_remove): """从 data 开头移除数据 (bytes) Args: len_to_remove (int): 要删除的数据长度 Returns: ret_data (list): 被删除的数据 """ ret_data = None try: if len_to_remove > 0: if len_to_remove < len(self.data): ret_data = self.data[:len_to_remove] self.data = self.data[len_to_remove:] else: ret_data = self.data[:] self.data.clear() except Exception as e: log.error("checker error when remove data: %s" % e) return ret_data
def start_threads_from_config(self): """读取配置文件,启动所有 rtk 线程""" # config configs = self.load_config() self.configs = configs # web 管理界面 try: port = configs['webInterface']['port'] if configs['webInterface']['allow'].lower() == 'true': self.start_web_interface(port) except Exception as e: log.error('main: failed to start web interface: %s' % e) # rtk 转发服务 try: if 'entry' in configs.keys(): self.start_rtk_threads(configs['entry']) except Exception as e: log.error('main: failed to start rtk threads: %s' % e) # web 管理界面的配置 try: if configs['webInterface']['allow'].lower() == 'true': self.update_web_interface(sorted(configs['entry'].keys())) except Exception as e: log.error('main: failed to update web interface: %s' % e)
def get_parsed_data(self): """解析数据 Returns: return (bytes): 解析了的完整报文 """ if len(self.data) <= 0: return None # 拷贝 data = self.data[:] if self.is_acceptable_msg_type is None: # 如果不用解析 self.data.clear() return bytes(data) try: # 解析 index, len_message, msg_type = try_parse(data) if index > 0: # 删除无法解析的数据 log.debug('unknown data size: %d' % index) # print unknown data # print([hex(x) for x in data[:index]]) # print(bytes(data[:index]).decode('utf-8', errors='ignore')) self.pop_front(index) if len_message > 0: # 删除解析后的数据 log.debug('pkg size: %d, msg size: %d, msg type: %d' % (len_message, len_message - 6, msg_type)) # print([hex(x) for x in data[:index + len_message]]) # print(bytes(data[:index + len_message]).decode('utf-8', errors='ignore')) parsed_data = bytes(self.pop_front(len_message)) if self.is_acceptable_msg_type(msg_type): return parsed_data except Exception as e: log.error('checker error when parse msg: %s' % e) return None
def run(self): """线程主函数 循环运行,接收来自客户端的数据并丢弃,向客户端发送 data_queue 中的数据包。 当 data_queue 过长时,丢弃旧的数据包。 """ log.info('sender thread %d: start, %s' % (self.sender_id, self.address)) try: while self.running: # ignore old data while self.data_queue.qsize() > 10: self.data_queue.get(block=False) # send data try: data = self.data_queue.get(timeout=1) self.client_socket.settimeout(5) self.client_socket.sendall(data) self.send_count += 1 self.data_queue.task_done() except queue.Empty: pass # rcv useless data try: self.client_socket.settimeout(0.1) rcv_buf = self.client_socket.recv(256) if len(rcv_buf) == 0: log.info('sender thread %d has disconnected.' % self.sender_id) # 退出 break except socket.timeout: pass except Exception as e: log.error('sender thread %d error: %s' % (self.sender_id, e)) self.disconnect() self.running = False log.info('sender thread %d: bye' % self.sender_id)
def load_config(): """载入配置文件 先读入 conf/config.json 中的配置,再读入 conf/ 中其他 json 文件里的 entry """ config_dir = os.path.join(sys.path[0], 'conf') configs = {} # main config config_file_name = os.path.join(config_dir, 'config.json') try: with open(config_file_name) as config_fp: configs = json.load(config_fp) except Exception as e: log.error('main: failed to load config from conf/config.json: %s' % e) if 'entry' not in configs.keys(): configs['entry'] = {} # other entries for dir_path, dir_names, file_names in os.walk(config_dir): for file_name in file_names: if file_name != 'config.json' and file_name.endswith('.json'): # load sub config config_file_name = os.path.join(config_dir, file_name) try: with open(config_file_name) as config_fp: sub_configs = json.load(config_fp) # insert into main config for name, config in sorted(sub_configs['entry'].items()): if name not in configs['entry'].keys(): configs['entry'][name] = config except Exception as e: log.error('main: failed to load config from conf/%s: %s' % (file_name, e)) # convert entries = {} for name, json_entry in configs['entry'].items(): try: entries[name] = Entry(json_entry) except Exception as e: log.error('failed to parse config %s: %s' % (name, e)) configs['entry'] = entries return configs
def start_threads_from_config(self, configs): """读取配置文件,启动所有 rtk 线程""" # web 管理界面 try: port = configs['webInterface']['port'] if configs['webInterface']['allow'].lower() == 'true': self.start_web_interface(port) except Exception as e: log.error('main: failed to start web interface: %s' % e) # rtk 转发服务 try: if 'entry' in configs.keys(): self.start_rtk_threads(configs['entry']) except Exception as e: log.error('main: failed to start rtk threads: %s' % e) # web 管理界面的配置 try: if configs['webInterface']['allow'].lower() == 'true': self.update_web_interface(sorted(configs['entry'].keys())) except Exception as e: log.error('main: failed to update web interface: %s' % e)