From 577a15c4005bf359b2cc36b2a69be6573155a36a Mon Sep 17 00:00:00 2001 From: YuanHongbin <975559679@qq.com> Date: Mon, 12 Oct 2026 10:24:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(ota):=20TCP(ETH)=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E9=80=9A=E9=81=93=E4=B8=8E=E5=8D=87=E7=BA=A7=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E9=87=8A=E6=94=BE=E8=BF=9E=E6=8E=A5,=20?= =?UTF-8?q?=E7=89=88=E6=9C=ACV1.3.0=20->=20V1.3.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 升级通道下拉新增TCP(ETH), 与TCP(Cat1)共用通道逻辑, ETH局域网升级打通 - TCP发送批次超时重置(3秒定时器重启动), 避免链路抖动后批次卡死 - 关闭升级页面主动释放连接: 停止TCP监听并断开所有已连客户端(shutdown+close), 关闭升级串口与接收线程 - 修复UpgradeDialog未初始化self.ser/_serial_rx导致closeEvent清理中断的问题 - TcpServerThread.stop统一收口: 关监听socket打断accept轮询+清空连接表, 按钮状态复位 --- gateway_config.py | 53 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/gateway_config.py b/gateway_config.py index 75d350e..9171777 100644 --- a/gateway_config.py +++ b/gateway_config.py @@ -294,8 +294,33 @@ class TcpServerThread(QThread): def stop(self): self.running = False + try: + if self.sock: + self.sock.close() # 打断accept轮询, run循环立即退出 + except Exception: + pass + self._close_all_clients() self.wait(3000) + def _close_all_clients(self): + """主动断开所有已连接客户端(网关模组的TCP链路随之释放, 对端能立刻感知断开)。""" + with self.conn_lock: + conns = list(self._conns.keys()) + self._conns.clear() + self.conn = None + self.target_ip = None + for conn in conns: + try: + conn.shutdown(socket.SHUT_RDWR) + except Exception: + pass + try: + conn.close() + except Exception: + pass + self._hexbufs.clear() + self._push_ip_list() + class GatewayConfigTool(QMainWindow): def __init__(self): @@ -315,7 +340,7 @@ class GatewayConfigTool(QMainWindow): self.refresh_ports() def init_ui(self): - self.setWindowTitle("网关配置工具(宽带版 V1.3.0)") + self.setWindowTitle("网关配置工具(宽带版 V1.3.1)") self.setWindowIcon(QIcon(resource_path("物联网网关.png"))) self.setMinimumSize(940, 640) self.resize(1000, 700) @@ -795,6 +820,8 @@ class UpgradeDialog(QDialog): self._timer = QTimer() self.channel = 'serial' # 升级通道: serial / tcp self.tcp_thread = None + self.ser = None # 升级通道串口对象(独立于主界面串口) + self._serial_rx = None # 升级串口接收线程 self._window = 8 # TCP模式每批包数(窗口流控) self._window_start = 0 # 当前批次首包序号(超时重发用) self._retry_cnt = 0 # TCP模式超时重发计数 @@ -832,7 +859,7 @@ class UpgradeDialog(QDialog): # 通道选择 + TCP监听 cfg_layout.addWidget(QLabel("通道:"), 2, 0) self.combo_channel = QComboBox() - self.combo_channel.addItems(["串口", "TCP(Cat1)"]) + self.combo_channel.addItems(["串口", "TCP(Cat1)", "TCP(ETH)"]) self.combo_channel.currentIndexChanged.connect(self._on_channel_changed) cfg_layout.addWidget(self.combo_channel, 2, 1) tcp_row = QHBoxLayout() @@ -1263,6 +1290,7 @@ class UpgradeDialog(QDialog): done = max(self._sent) + 1 self.progress.setValue(min(int(done * 100.0 / self._pkg_num), 100)) self.status_lbl.setText(f"{done}/{self._pkg_num} 包") + self._timer.start(3000) # 批次发完重置超时: 防止上次定时器虚假触发(REQ已处理仍判超时) if len(self._sent) >= self._pkg_num: self._finish() @@ -1309,8 +1337,25 @@ class UpgradeDialog(QDialog): self._cancel_upgrade() else: self._release_session() - if self.ser and self.ser.is_open: - self._toggle_serial() + # 升级TCP通道: 停止监听并主动断开已连接的客户端, 释放网关模组建立的TCP链路 + if self.tcp_thread is not None: + if self.tcp_thread.isRunning(): + self.tcp_thread.stop() + self.tcp_thread = None + self.btn_tcp_listen.setText("开始监听") + # 串口通道: 关闭升级页面打开的串口 + if self.ser is not None: + if self._serial_rx is not None: + self._serial_rx.stop() + self._serial_rx = None + try: + self.ser.close() + except Exception: + pass + self.ser = None + self.btn_serial_open.setText("打开串口") + self.serial_status_lbl.setText("未打开") + self.serial_status_lbl.setStyleSheet("color:#909090;") self._reset_ui() event.accept()