From a8c684ad0c118f303de32dfb2399cc5b305fdea1 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Mon, 15 Jun 2026 12:09:34 +0800 Subject: [PATCH] =?UTF-8?q?fix(client):=20=E5=8D=95=E5=AE=9E=E4=BE=8B?= =?UTF-8?q?=E9=94=81=E6=94=B9=E7=94=A8=20TCP=20loopback=20socket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 文件锁在 Windows 上行为不一致,改用绑定本地端口(54317)作为互斥锁, 进程退出时 OS 自动释放,Windows/macOS 均可靠生效。 Co-Authored-By: Claude Sonnet 4.6 --- client/lib/core/platform/single_instance.dart | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/client/lib/core/platform/single_instance.dart b/client/lib/core/platform/single_instance.dart index 0e20c7c..6c0af12 100644 --- a/client/lib/core/platform/single_instance.dart +++ b/client/lib/core/platform/single_instance.dart @@ -1,11 +1,13 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; -import 'package:path_provider/path_provider.dart'; -// Keep the RAF open so the OS lock stays alive for the lifetime of the process. -// ignore: unused_element -RandomAccessFile? _raf; +// Keep the server socket alive for the lifetime of the process. +// The OS releases the port automatically when the process exits. +ServerSocket? _server; + +// Port unique to this app; chosen from the private range 49152–65535. +const _kLockPort = 54317; /// Returns true if this process successfully acquired the single-instance lock. /// Returns false if another instance is already running. @@ -15,11 +17,11 @@ Future acquire() async { if (!Platform.isWindows && !Platform.isMacOS) return true; try { - final dir = await getApplicationSupportDirectory(); - final lockFile = File('${dir.path}/jiu.lock'); - final raf = await lockFile.open(mode: FileMode.write); - await raf.lock(FileLock.exclusive); - _raf = raf; + _server = await ServerSocket.bind( + InternetAddress.loopbackIPv4, + _kLockPort, + shared: false, + ); return true; } catch (_) { return false;