修复bug

This commit is contained in:
2025-11-05 17:07:51 +08:00
parent 242c2e99c5
commit 01e18bdc03
10 changed files with 497 additions and 202 deletions

View File

@@ -103,39 +103,59 @@ def _apply_device_event(obj: Dict[str, Any]):
# ============ 设备事件 socket 监听 ============
def _handle_conn(conn: socket.socket, addr):
"""统一的连接处理函数(外部全局,避免内嵌函数覆盖"""
"""统一的连接处理函数(拆 JSON 行 → 正常化 type → 应用到 listData"""
try:
with conn:
try:
conn.settimeout(3.0) # 避免永久阻塞
except Exception:
pass
buffer = ""
while True:
data = conn.recv(1024)
if not data: # 对端关闭
break
buffer += data.decode('utf-8', errors='ignore')
# 按行切 JSON发送端每条以 '\n' 结尾
while True:
line, sep, buffer = buffer.partition('\n')
if not sep:
try:
data = conn.recv(1024)
if not data: # 对端关闭
break
line = line.strip()
if not line:
continue
try:
obj = json.loads(line)
except json.JSONDecodeError as e:
LogManager.warning(f"[SOCKET][WARN] 非法 JSON 丢弃: {line[:120]} err={e}")
continue
dev_id = obj.get("deviceId")
typ = _normalize_type(obj.get("type", 1))
obj["type"] = typ
LogManager.info(f"[SOCKET][RECV] deviceId={dev_id} type={typ} keys={list(obj.keys())}")
_apply_device_event(obj)
LogManager.info(f"[SOCKET][APPLY] deviceId={dev_id} type={typ}")
buffer += data.decode('utf-8', errors='ignore')
# 按行切 JSON发送端每条以 '\n' 结尾
while True:
line, sep, buffer = buffer.partition('\n')
if not sep:
break
line = line.strip()
if not line:
continue
try:
obj = json.loads(line)
except json.JSONDecodeError as e:
LogManager.warning(f"[SOCKET][WARN] 非法 JSON 丢弃: {line[:120]} err={e}")
continue
dev_id = obj.get("deviceId")
typ = _normalize_type(obj.get("type", 1))
obj["type"] = typ # 规范 1/0
LogManager.info(f"[SOCKET][RECV] deviceId={dev_id} type={typ} keys={list(obj.keys())}")
try:
_apply_device_event(obj) # ← 保持你的原设备增删逻辑
LogManager.info(f"[SOCKET][APPLY] deviceId={dev_id} type={typ}")
except Exception as e:
# 单条业务异常不让线程死
LogManager.error(f"[DEVICE][APPLY_EVT][ERROR] {e}")
except (socket.timeout, ConnectionResetError, BrokenPipeError):
# 连接级异常:关闭该连接,回到 accept
break
except Exception as e:
LogManager.warning(f"[SOCKET][WARN] recv error: {e}")
break
except Exception as e:
LogManager.error(f"[SOCKET][ERROR] 连接处理异常: {e}")
def start_socket_listener():
"""启动设备事件监听(与 HTTP 端口无关,走 FLASK_COMM_PORT"""
"""启动设备事件监听(走 FLASK_COMM_PORT;增强健壮性,不改业务"""
# 统一使用 FLASK_COMM_PORT默认 34566
port = int(os.getenv('FLASK_COMM_PORT', 34566))
LogManager.info(f"Received port from environment: {port}")
@@ -146,29 +166,64 @@ def start_socket_listener():
print("未获取到通信端口跳过Socket监听")
return
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.bind(('127.0.0.1', port))
print(f"[INFO] Socket successfully bound to port {port}")
LogManager.info(f"[INFO] Socket successfully bound to port {port}")
except Exception as bind_error:
print(f"[ERROR]端口绑定失败: {bind_error}")
LogManager.info(f"[ERROR]端口绑定失败: {bind_error}")
return
s.listen()
LogManager.info(f"[INFO] Socket listener started on port {port}, waiting for connections...")
print(f"[INFO] Socket listener started on port {port}, waiting for connections...")
backoff = 0.5 # 自愈退避,起于 0.5s,上限 8s
while True:
s = None
try:
conn, addr = s.accept()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except Exception as e:
LogManager.warning(f"[SOCKET][WARN] setsockopt SO_REUSEADDR failed: {e}")
try:
s.bind(('127.0.0.1', port))
print(f"[INFO] Socket successfully bound to port {port}")
LogManager.info(f"[INFO] Socket successfully bound to port {port}")
except Exception as bind_error:
print(f"[ERROR]端口绑定失败: {bind_error}")
LogManager.info(f"[ERROR]端口绑定失败: {bind_error}")
# 绑定失败通常是端口未释放/竞争,退避后重试
time.sleep(backoff)
backoff = min(backoff * 2, 8.0)
continue
s.listen()
try:
s.settimeout(1.5) # accept 超时,便于检查自愈循环
except Exception:
pass
LogManager.info(f"[INFO] Socket listener started on port {port}, waiting for connections...")
print(f"[INFO] Socket listener started on port {port}, waiting for connections...")
# 监听成功 → 退避复位
backoff = 0.5
while True:
try:
conn, addr = s.accept()
except socket.timeout:
# 定期“透气”,避免永久卡死;继续等待
continue
except Exception as e:
# 发生 accept 级错误:重建 socket进入外层 while 自愈)
LogManager.error(f"[ERROR] accept 失败: {e}")
break
# 每个连接独立线程处理,保持你原来的做法
threading.Thread(target=_handle_conn, args=(conn, addr), daemon=True).start()
except Exception as e:
LogManager.error(f"[ERROR] accept 失败: {e}")
continue
threading.Thread(target=_handle_conn, args=(conn, addr), daemon=True).start()
# 任意未兜住的异常,记录并进入退避自愈
LogManager.error(f"[SOCKET][ERROR] 监听主循环异常: {e}")
time.sleep(backoff)
backoff = min(backoff * 2, 8.0)
finally:
try:
if s:
s.close()
except Exception:
pass
# 独立线程启动 Socket 服务 + 看门狗
listener_thread = threading.Thread(target=start_socket_listener, daemon=True)