修复bug
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user