def run(self): """线程主函数 循环运行,接受新的客户端的连接。 """ log.info('server 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: try: conn, address = server.accept() conn.settimeout(3) self.got_client_cb(conn, address) log.debug('new client from: %s' % str(address)) except socket.timeout: pass server.close() log.info('server thread: bye') except Exception as e: log.error('server thread error: %s' % e) self.running = False
def run(self): """线程主函数 循环运行,接受到控制端口的 socket 连接(唯一),接收命令。 """ 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 receive_data(self): """建立连接并循环接收数据 在超时时重连,在出错时返回。 """ client = self.connect() log.info('client thread: connected') timeout_count = 0 while self.running: try: # 接收数据 data = client.recv(BUFFER_SIZE) # 连接失败的处理 if len(data) == 0: raise RuntimeError('socket connection broken') # 收到数据后的处理 self.rcv_count += 1 log.debug('rcv %d bytes. id: %d' % (len(data), self.rcv_count)) self.got_data_cb(data, self.rcv_count) timeout_count = 0 except socket.timeout: # 超时处理,超时5次时主动重连 # 超时时间短是为了在需要时能快速退出 timeout_count += 1 if timeout_count >= 5: timeout_count = 0 client = self.reconnect(client) log.debug('client timeout, reconnect') try: client.close() except socket.error: pass except Exception as e: log.error('client exception when close: %s' % e)
def run(self): """线程主函数 循环运行,建立连接、接收数据,并在连接出错时重连。 """ log.info('client thread: start') while self.running: try: self.receive_data() except Exception as e: log.error('client thread error: %s' % e) time.sleep(3) log.info('client thread: bye')
def accept_client(self, server): """监听控制端口 尝试接受连接,如果有新连接,就关闭旧的连接。 Args: server: server socket """ try: conn, address = server.accept() self.disconnect_client() self.client = conn self.client.settimeout(3) log.info('new control client from: %s' % str(address)) except socket.timeout: pass
def run(self): """线程主函数 循环运行,不断把 self.data_queue 中的数据包分发给各 SenderThread """ log.info('dispatcher thread: start') while self.running: try: data, rcv_count = self.data_queue.get(timeout=1) try: num_clients = self.send_data(data) self.data_queue.task_done() log.debug('send %d bytes to %d clients. id: %d' % (len(data), num_clients, rcv_count)) except Exception as e: log.error('dispatcher thread error: %s' % e) except queue.Empty: pass self.stop_all_clients() log.info('dispatcher thread: bye')
def main(self): # config config_file_name = os.path.join(sys.path[0], 'conf/config.json') try: with open(config_file_name) as config_fp: configs = json.load(config_fp) except: print('failed to load config from config.json.') return # log init log.initialize_logging(configs['enableLog'].lower() == 'true') log.info('main: start') # threads self.server = ServerThread(configs['listenPort'], self.got_client_cb) self.controller = ControlThread(configs['controlPort'], self.got_command_cb) self.dispatcher = DispatcherThread(self.pcb_manager.on_recv_heartbeat) self.client = ClientThread(configs['serverIpAddress'], configs['serverPort'], self.got_data_cb) self.server.start() self.controller.start() self.dispatcher.start() self.client.start() # wait self.wait_for_keyboard() # quit & clean up self.controller.running = False self.controller.join() self.client.running = False self.client.join() self.server.running = False self.server.join() self.dispatcher.running = False self.dispatcher.join() log.info('main: bye')
def resolve_command(self): """解析来自控制端口的数据 首先寻找指令起始标记,找不到就从 buffer 头删除一个字节,再继续寻找。 然后调用 resolve_command_from_begin() 从 buffer 的开头开始解析,直到遇到结尾标记为止。 """ while len(self.buffer) >= 4: # 解析指令 try: if self.is_in_command: # 指令从 buffer[0] 开始 command = self.resolve_command_from_begin() if self.is_in_command: # 没有遇到结尾,收到的指令还不完整 break elif isinstance(command, str): # 收到了指令 log.info('control command: %s' % command) self.got_command_cb(command) elif self.buffer[:4] == CMD_BEGIN: # begin of command self.is_in_command = True else: del self.buffer[0] # 出队一个字节 except Exception as e: log.warning('control thread resolve: %s' % e)
def run(self): """线程主函数 循环运行,接收来自客户端的数据并丢弃,向客户端发送 data_queue 中的数据包。 当 data_queue 过长时,丢弃旧的数据包。 """ log.info('sender thread %d: start, %s' % (self.sender_id, self.address)) while self.running: try: # ignore old data if self.data_queue.qsize() > 10: self.data_queue.empty() # 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 except ValueError as e: log.warning('sender thread %d ValueError: %s' % (self.sender_id, e)) # rcv heartbeat data try: self.client_socket.settimeout(1) new_recv_data = self.client_socket.recv(1024) if len(new_recv_data) > 0: self.data_received += new_recv_data self.parse_heartbeat_recv_buffer() # 分包 except socket.timeout: pass except Exception as e: log.error('sender thread %d error: %s' % (self.sender_id, e)) self.running = False self.disconnect() log.info('sender thread %d: bye' % self.sender_id)