From c875cf383ba9cb149a7d48fe23f2d102b622b475 Mon Sep 17 00:00:00 2001 From: wangfq Date: Wed, 10 Jun 2026 10:01:07 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20HeartBeat=20?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E5=86=99=E4=B8=8D=E5=8C=B9=E9=85=8D=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E4=BA=A4=E4=BA=92=E6=9C=AA=E8=A2=AB=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根本原因: 设备发送 Method='HeartBeat'(大写B), 代码匹配'Heartbeat'(小写b), 心跳包被静默忽略, record_interaction 未调用, 导致监控误判为离线。 修复: - UDP/TCP 方法匹配改为 case-insensitive (method_lower) - handle_timestamp 增加 record_interaction 调用 (TimeStamp 也是设备交互) - TCP 连接/断开时写入 tb_device_log 事件日志 (tcp_connect/tcp_disconnect) --- src/handlers.py | 16 +++------------- src/server.py | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/handlers.py b/src/handlers.py index c768e0d..a696ca7 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -187,21 +187,11 @@ async def handle_heartbeat(data: dict) -> str | None: def handle_timestamp(data: dict) -> str: - """处理时间同步请求 - - TimeStamp 请求格式: - { - "Method": "TimeStamp", - "Params": { - "Device_id": "2345", - "TimeZone": "Asia/Shanghai" - } - } - - 返回格式参考 PGLC 协议 3.5 节。 - """ + """处理时间同步请求(也是设备交互)""" params = data.get("Params", {}) device_id = params.get("Device_id", "") + if device_id: + record_interaction(device_id) return make_timestamp_response(device_id, int(time.time())) diff --git a/src/server.py b/src/server.py index c5c4711..80a707e 100644 --- a/src/server.py +++ b/src/server.py @@ -37,6 +37,7 @@ from src.handlers import ( device_status_monitor, set_udp_sender, ) +from src.models import insert_device_log logging.basicConfig( level=getattr(logging, LOG_LEVEL), @@ -75,6 +76,7 @@ class EDCProtocol: logger.info(f"UDP {msg} from {addr}") method = msg.get("Method", "") + method_lower = method.lower() logger.debug(f"UDP {method} from {addr}") try: @@ -82,11 +84,11 @@ class EDCProtocol: if method == "Count_Off": # 设备登录上报,只处理不回复 await handle_count_off(msg, addr) - elif method == "Heartbeat": + elif method_lower == "heartbeat": response = await handle_heartbeat(msg) - elif method == "TSReport": + elif method_lower == "tsreport": response = await handle_tsreport(msg) - elif method == "SerialNet": + elif method_lower == "serialnet": response = await handle_serial_net(msg) if response and self.transport: @@ -105,24 +107,36 @@ async def handle_tcp_client(reader: asyncio.StreamReader, - 紧凑 JSON (无换行) """ addr = writer.get_extra_info("peername") + addr_ip = addr[0] if addr else "" logger.info(f"TCP 连接: {addr}") + # TCP 连接事件日志 + try: + asyncio.ensure_future(insert_device_log( + serial="", ip=addr_ip, + event_type="tcp_connect", + content=f"TCP 连接: {addr}", + )) + except Exception: + pass + buffer = b"" async def process_message(msg: dict): """处理单条消息并返回响应文本""" logger.info(f"TCP get_rcv {msg} from {addr}") method = msg.get("Method", "") + method_lower = method.lower() logger.debug(f"TCP {method} from {addr}") try: - if method == "TimeStamp": + if method_lower == "timestamp": return handle_timestamp(msg) - elif method == "TSReport": + elif method_lower == "tsreport": return await handle_tsreport(msg) - elif method == "SerialNet": + elif method_lower == "serialnet": return await handle_serial_net(msg) - elif method == "Heartbeat": + elif method_lower == "heartbeat": return await handle_heartbeat(msg) else: logger.debug(f"TCP 未知方法: {method}") @@ -176,6 +190,15 @@ async def handle_tcp_client(reader: asyncio.StreamReader, pass finally: logger.info(f"TCP 断开: {addr}") + # TCP 断开事件日志 + try: + asyncio.ensure_future(insert_device_log( + serial="", ip=addr_ip, + event_type="tcp_disconnect", + content=f"TCP 断开: {addr}", + )) + except Exception: + pass writer.close() await writer.wait_closed()