def get_active_pcbs_info(self): """读取当前客户列表""" pcb_info_list = b'' # 检查 pcb 表 self.lock.acquire() try: for device_id, pcb in self.pcbs.copy().items(): if not pcb.is_alive(): del self.pcbs[device_id] else: line = ( pcb.device_id, pcb.status, bytes(pcb.timestamp_init.strftime('%Y/%m/%d,%H:%M:%S'), 'utf-8'), bytes( pcb.timestamp_last_active.strftime( '%Y/%m/%d,%H:%M:%S'), 'utf-8')) pcb_info_list += b'-'.join(line) + b'\r\n' except Exception as e: log.error('pcb manager: when get pcb info: %s' % e) self.lock.release() return bytes('%d\r\n' % len(pcb_info_list), 'utf-8') + pcb_info_list + b'$bye\r\n'
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 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 reconnect(self, client): """重连 socket""" try: client.close() except: log.error('client exception when close.') return self.connect()
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 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 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 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 on_recv_heartbeat(self, sender_id, heartbeat, timestamp): """收到一条完整心跳包时的处理函数 由各 sender_thread 调用 Args: sender_id: 收到心跳包的线程 ID heartbeat (bytes): 心跳包 timestamp: 收到心跳包的时间 """ log.debug('pcb manager: from sender %d: %s' % (sender_id, heartbeat)) self.lock.acquire() try: self.parse_heartbeat(heartbeat, timestamp) except Exception as e: log.error('pcb manager: when parse from sender %d: %s' % (sender_id, e)) self.lock.release()
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 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 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)