This commit is contained in:
2026-06-08 17:52:53 +08:00
parent 9654b79cec
commit 49a84e80e1
4 changed files with 91 additions and 47 deletions

View File

@@ -72,6 +72,10 @@ class NetworkManager:
self._raw_line_data = []
self._manual_trigger_flag = False
# 限制并发命令线程数
self._cmd_thread_lock = threading.Lock()
self._cmd_thread_count = 0
# 网络类型状态
self._network_type = None # "wifi" 或 "4G" 或 None
# 本次上电曾因 WiFi 质量差切换到 4G 后,直至关机不再改回 WiFi
@@ -165,11 +169,15 @@ class NetworkManager:
self._password = password
def _enqueue(self, item, high=False):
"""线程安全地加入队列(内部方法)"""
"""线程安全地加入队列(内部方法),队列满时丢弃最旧消息"""
with self._queue_lock:
if high:
if len(self._high_send_queue) >= config.MAX_SEND_QUEUE_SIZE:
self._high_send_queue.pop(0)
self._high_send_queue.append(item)
else:
if len(self._normal_send_queue) >= config.MAX_SEND_QUEUE_SIZE:
self._normal_send_queue.pop(0)
self._normal_send_queue.append(item)
self._send_event.set()
@@ -198,6 +206,29 @@ class NetworkManager:
"""获取队列锁用于with语句"""
return self._queue_lock
def _spawn_cmd_thread(self, target, args=()):
"""安全创建命令线程,限制并发数,防止无限创建导致内存耗尽"""
with self._cmd_thread_lock:
if self._cmd_thread_count >= config.MAX_CMD_THREADS:
self.logger.warning(
f"[NET] 并发命令线程已达上限({config.MAX_CMD_THREADS}),跳过: {getattr(target, '__name__', str(target))}"
)
return False
self._cmd_thread_count += 1
def _wrapper(*a):
try:
target(*a)
except Exception as e:
self.logger.error(f"[NET] 命令线程异常: {e}")
finally:
with self._cmd_thread_lock:
self._cmd_thread_count -= 1
import _thread
_thread.start_new_thread(_wrapper, args)
return True
# ==================== 业务方法 ====================
def read_device_id(self):
@@ -1728,8 +1759,6 @@ class NetworkManager:
def tcp_main(self):
"""TCP 主通信循环:登录、心跳、处理指令、发送数据"""
import _thread
self.logger.info("[NET] TCP主线程启动")
send_hartbeat_fail_count = 0
@@ -1965,8 +1994,7 @@ class NetworkManager:
self.logger.info(f"[IMAGE_UPLOAD] 准备上传: {target_image} -> {key}")
# 在新线程中执行上传,避免阻塞主循环
import _thread
_thread.start_new_thread(
self._spawn_cmd_thread(
self._upload_image_file,
(target_image, upload_url, upload_token, key, shoot_id, outlink)
)
@@ -1994,8 +2022,7 @@ class NetworkManager:
else:
self.logger.info(f"[LOG_UPLOAD] 收到日志上传命令key: {key}")
# 在新线程中执行上传,避免阻塞主循环
import _thread
_thread.start_new_thread(
self._spawn_cmd_thread(
self._upload_log_file_v2,
(upload_url, upload_token, key, outlink, include_rotated, max_files,
archive_format)
@@ -2110,7 +2137,7 @@ class NetworkManager:
if mode == "4g":
ota_manager._set_ota_url(ota_url) # 记录 OTA URL供命令7使用
ota_manager._start_update_thread()
_thread.start_new_thread(ota_manager.direct_ota_download_via_4g, (ota_url,))
self._spawn_cmd_thread(ota_manager.direct_ota_download_via_4g, (ota_url,))
else: # mode == "wifi"
if not ssid or not password:
self.logger.error("ota wifi mode requires ssid and password")
@@ -2119,7 +2146,7 @@ class NetworkManager:
self.logger.info(f"ssid: {ssid}")
self.logger.info(f"password: {password}")
ota_manager._start_update_thread()
_thread.start_new_thread(ota_manager.handle_wifi_and_update,
self._spawn_cmd_thread(ota_manager.handle_wifi_and_update,
(ssid, password, ota_url))
elif inner_cmd == 6:
try:
@@ -2179,25 +2206,21 @@ class NetworkManager:
2)
else:
self.logger.info(f"[LOG_UPLOAD] 收到日志上传命令目标URL: {upload_url}")
# 在新线程中执行上传,避免阻塞主循环
import _thread
_thread.start_new_thread(
self._upload_log_file,
(upload_url, wifi_ssid, wifi_password, include_rotated, max_files,
archive_format)
)
# 在新线程中执行上传,避免阻塞主循环
self._spawn_cmd_thread(
self._upload_log_file,
(upload_url, wifi_ssid, wifi_password, include_rotated, max_files,
archive_format)
)
elif inner_cmd == 200:
self.logger.info("[LASER] cmd200 在后台线程执行检测")
import _thread
_thread.start_new_thread(self._cmd200_detect_laser, ())
self._spawn_cmd_thread(self._cmd200_detect_laser, ())
elif inner_cmd == 300:
self.logger.info("[New Ota] cmd300 在后台线程执行OTA")
import _thread
_thread.start_new_thread(self._cmd300_ota, (data_obj,))
self._spawn_cmd_thread(self._cmd300_ota, (data_obj,))
elif inner_cmd == 600:
self.logger.info("[conn wifi] cmd600 在后台线程执行连接wifi: {data_obj}")
import _thread
_thread.start_new_thread(self._cmd600_conn_wifi, (data_obj,))
self._spawn_cmd_thread(self._cmd600_conn_wifi, (data_obj,))
elif inner_cmd == 601:
pass
else: # data的结构不是 dict
@@ -2228,12 +2251,14 @@ class NetworkManager:
msg_type, data_dict = item
pkt = self._netcore.make_packet(msg_type, data_dict)
if not self.tcp_send_raw(pkt):
# 发送失败:将消息放回队首,触发重连(避免丢消息
# 发送失败:将消息放回队首(队列满则丢弃
with self.get_queue_lock():
if item_is_high:
self._high_send_queue.insert(0, item)
if len(self._high_send_queue) < config.MAX_SEND_QUEUE_SIZE:
self._high_send_queue.insert(0, item)
else:
self._normal_send_queue.insert(0, item)
if len(self._normal_send_queue) < config.MAX_SEND_QUEUE_SIZE:
self._normal_send_queue.insert(0, item)
self._tcp_connected = False
try:
self.disconnect_server()