def begin_test(self): self.running = True self.endFuture = asyncio.Future() # 启动listen_to_t协程 asyncio.run_coroutine_threadsafe(self.listen_to_t(), asyncio.get_event_loop()) b4.send_line(self.tw, 'i=1')
def handle_room_msg(self, room_id: int, msg: dict) -> bool: """ 处理房间发来的消息 目前看来只有定时消息和关闭空调消息 :param room_id: 发来消息的房间号 :param msg: 消息 :return: 如果关闭空调则返回False """ room_info = self.rooms[room_id - 1] if 'tc' in msg.keys(): msg_tc = int(msg['tc']) if 'it' in msg.keys(): cur_t = int(msg['t']) print( f'room={room_id} on={room_info.on} it={room_info.it} tt={room_info.tt} room_tc={room_info.tc}' ) # 计费 if room_info.on: msg_tt = int(msg['tt']) if msg_tt != room_info.tt or 'w' in msg: if cur_t != room_info.tt: # 没有保持目标温度 room_info.bill += abs(cur_t - room_info.it) print('1: ' + str(abs(cur_t - room_info.it))) else: room_info.bill += abs( room_info.tt - room_info.it) * (1 + msg_tc - room_info.tc) print('2: ' + str( abs(room_info.tt - room_info.it) * (1 + msg_tc - room_info.tc))) # 重置 room_info.it = int(msg['it']) room_info.tt = int(msg['tt']) else: # 初始化 room_info.it = int(msg['it']) room_info.tt = int(msg['tt']) if 'w' in msg.keys(): room_info.on = False b4.send_line(self.tw, f'r={room_id} tc={msg_tc} w=0') log.info(f'r={room_id} tc={msg_tc} w=0') return False else: room_info.on = True elif 't' in msg.keys(): # 定时信息 # 如果尚未达到目标温度,则更新当前温度和tc if room_info.cur_t is None or room_info.cur_t != int(msg['t']): room_info.cur_t = int(msg['t']) room_info.tc = int(msg_tc) log.info( f"UPDATE: cur_t={room_info.cur_t}, tc={room_info.tc}") b4.send_line(self.tw, f'r={room_id} tc={msg_tc} t={msg["t"]}') log.info(f'r={room_id} tc={msg_tc} t={msg["t"]}') return True
async def start(self): running = True step = 1 while running: msg = await b4.recv_line(self.tr) if 'tc' in msg: self.cur_timer += 1 # 使原来的定时器无效 msg_tc = int(msg['tc']) if 'ts' in msg: self.ts = float(msg['ts']) # 校正当前温度 dt = int((msg_tc - self.begin_tc) / (4 - self.w)) * step if abs(dt) > abs(self.tt - self.it): t = self.tt else: t = self.it + dt if 'w' in msg: self.w = int(msg['w']) self.it = t if 'tt' in msg: self.tt = int(msg['tt']) self.it = int(msg['it']) step = 1 if self.tt > self.it else -1 if self.w == 0: b4.send_line( self.sw, f'tc={msg_tc} it={self.it} tt={self.tt} t={t} w=0') running = False else: b4.send_line( self.sw, f'tc={msg_tc} it={self.it} tt={self.tt} t={t}') self.begin_tc = msg_tc asyncio.run_coroutine_threadsafe( self.timer(self.begin_tc, self.cur_timer), asyncio.get_event_loop()) try: # 监听连接,等待服务器关闭连接,关闭后抛出异常即可结束协程 await b4.recv_line(self.sr) except Exception as e: log.info('Close the server connection') print(e) self.close()
async def login(self, host: str, port: int, k: str) -> bool: """ 服务器登录到test的协程 :param host: test的host :param port: test的端口 :param k: 密钥 :return: 登录成功返回True """ try: self.tr, self.tw = await asyncio.open_connection(host, port) b4.send_line(self.tw, f'k={k} r=s') rl = await b4.recv_line(self.tr, 'e') log.info("Server Login") return len(rl) == 1 and rl[0] == '0' except Exception as e: print(e) self.close() return False
async def listen_to_t(self): while self.roomLoggedIn > 0: # 仍有房间没有测试完成 rl = await b4.recv_line(self.tr, 'b', 'tc') log.info(f"Received billing: {rl}") room_id = int(rl[0]) # 房间号 if 1 <= room_id <= len(self.rooms): tc = int(rl[1]) log.info(f"Check enter loop: tc={tc} room_id={room_id}") room_info = self.rooms[room_id - 1] # 返回"r={房间号} tc={tc} b={费用}" b4.send_line(self.tw, f'r={room_id} tc={tc} b={room_info.bill}') log.info( f'Send to test: r={room_id} tc={tc} b={room_info.bill}') self.rooms[room_id - 1] = None # 房间测试通过,标记为登出 self.roomLoggedIn -= 1 print('测试结束,按回车退出') input() self.endFuture.set_result(1) # 全部完成,允许连接断开 asyncio.get_event_loop().stop() # 消息循环可以结束 self.close() # 断开与test的连接
async def _client_connected(self, r: asyncio.StreamReader, w: asyncio.StreamWriter): """ 房间连接回调协程,连接建立后此协程处理该房间整个测试流程 :param r: 房间到服务器的tcp输入流 :param w: 服务器到房间的tcp输出流 :return: """ peer_host, peer_port, *_ = w.get_extra_info('peername') room_id = 0 try: msg = await b4.recv_line(r, 'r') room_id = int(msg[0]) log.info(f'msg:{msg}') if 1 <= room_id <= len( self.rooms) and self.rooms[room_id - 1] is None: # 房间号在规定范围内且没有重复,成功登录 b4.send_line(w, 'e=0') self.rooms[room_id - 1] = RoomInfo(r, w) # 添加房间信息 self.roomLoggedIn += 1 if self.roomLoggedIn == len(self.rooms): # 所有房间都已登录,开始测试 log.info("All room logged in, begin test...") self.begin_test() while True: msg = await b4.recv_line(r) # 取一个消息 log.info(f'handling msg:{msg}') if not self.handle_room_msg(room_id, msg): break else: # 非法房间号 b4.send_line(w, 'e=InvalidRoom') except Exception as e: print(e) # 测试还没开始到达此处,表示房间登录失败,清除记录 if not self.running and 1 <= room_id <= len(self.rooms): self.rooms[room_id - 1] = None self.roomLoggedIn -= 1 if self.endFuture: # 还有房间没有完成,等结束后再断开连接 await self.endFuture self.endFuture = None w.close()
async def timer(self, tc, timer_id): """ 定时更新状态及发送消息的协程 """ t = self.it # 当前温度 time_step = 1 if self.it < self.tt else -1 log.info(f"it={self.it} up={time_step}") log.info(f"w is {self.w}") while self.cur_timer == timer_id: # 当前定时器有效 b4.send_line(self.sw, f'tc={tc} t={t}') log.info(f'Send to server: tc={tc} t={t}') # 更新温度和时间 if t != self.tt: # 还没达到目标温度,每变化1度发送一次状态 t += time_step delay = 4 - self.w else: # 已经达到目标温度处于保持状态,每秒发送一次状态 delay = 1 # 模拟时间变化 tc += delay await asyncio.sleep(delay * self.ts)
async def login(self, t_host: str, t_port: int, s_host: str, s_port: int, k: str) -> bool: """ 房间登录到test和服务器的协程 :param t_host: test的host :param t_port: test的端口 :param s_host: 服务器的host :param s_port: 服务器的端口 :param k: 验收分配的密钥 :return: test和服务器均登录成功返回True """ ev_loop = asyncio.get_event_loop() try: # 连接并登录test self.tr, self.tw = await asyncio.open_connection(t_host, t_port, loop=ev_loop) b4.send_line(self.tw, f'k={k} r={self.id}') rl = await b4.recv_line(self.tr, 'e') if len(rl) == 1 and rl[0] == '0': # test登录成功,连接并登录服务器 log.info("Connected to the test program") self.sr, self.sw = await asyncio.open_connection(s_host, s_port, loop=ev_loop) b4.send_line(self.sw, f'r={self.id}') rl = await b4.recv_line(self.sr, 'e') if len(rl) == 1 and rl[0] == '0': # 服务器登录成功 log.info("Connected to the server") return True except ConnectionRefusedError as e: print(e) self.close() return False