From 93716d484d3b6761c3a66ea54bd083d0d8bf16aa Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=B0=8F=E9=BE=99?= Date: Mon, 20 Jul 2026 11:45:56 +0800 Subject: [PATCH] =?utf8?q?Socket=E7=AB=AF=E5=8F=A3=E7=BB=91=E5=AE=9A?= =?utf8?q?=E6=9B=BF=E4=BB=A3=E6=96=87=E4=BB=B6=E9=94=81=20v3.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- wechat_auto_login.py | 56 ++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/wechat_auto_login.py b/wechat_auto_login.py index 92c00a5..8bd13a9 100644 --- a/wechat_auto_login.py +++ b/wechat_auto_login.py @@ -18,7 +18,7 @@ try: import random import logging import configparser - import atexit + import socket import tempfile import base64 @@ -56,36 +56,35 @@ try: log.critical("导入第三方库失败: %s", e) sys.exit(1) - # ── single instance lock ───────────────────────────────────────────────── - _lock_file = os.path.join(tempfile.gettempdir(), "wechat_auto_login.lock") - _lock_fd = None + class SingleInstance: + """基于Socket端口绑定的单实例保护。进程死OS自动释放端口,零残留。""" + def __init__(self, app_name="wechat_auto_login", port=52001): + self._sock = None + self._port = port + self.app_name = app_name - - def _acquire_lock(): - global _lock_fd - try: - _lock_fd = os.open(_lock_file, os.O_CREAT | os.O_EXCL | os.O_RDWR) - return True - except FileExistsError: - return False - - - def _release_lock(): - global _lock_fd - if _lock_fd is not None: - os.close(_lock_fd) + def try_lock(self): try: - os.unlink(_lock_file) + self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._sock.bind(("127.0.0.1", self._port)) + self._sock.listen(1) + return True except OSError: - pass + return False + + def release(self): + if self._sock: + try: + self._sock.close() + except OSError: + pass + self._sock = None # ── 模块初始化(用 try 捕获所有意外错误) ─────────────────────────────── try: - if not _acquire_lock(): - log.error("已有实例在运行,退出") - sys.exit(1) - atexit.register(_release_lock) + # ── config ───────────────────────────────────────────────────────────────── config = configparser.ConfigParser() @@ -850,8 +849,15 @@ try: def main(): + si = SingleInstance() + if not si.try_lock(): + log.error("已有实例在运行") + sys.exit(1) app = MonitorApp() - app.root.mainloop() + try: + app.root.mainloop() + finally: + si.release() if __name__ == "__main__": -- 2.43.0