Compare commits

..
3 Commits
Author SHA1 Message Date
kislovdm 8d30ee4af1 Рефакторинг имени клода
.NET Core Desktop / build (Debug) (push) Has been cancelled
2026-07-17 14:18:28 +03:00
kislovdm 1db62a8574 Merge branch 'master' of github.com:monster1025/monster_monitor_v2 2026-07-17 14:18:02 +03:00
kislovdm 83801d78c4 fix 2026-07-17 14:17:10 +03:00
3 changed files with 135 additions and 5 deletions
+1 -1
View File
@@ -1 +1 @@
1.0.24 1.0.25
+4 -4
View File
@@ -6,10 +6,10 @@
<LangVersion>7.3</LangVersion> <LangVersion>7.3</LangVersion>
<RootNamespace>MonsterMonitor</RootNamespace> <RootNamespace>MonsterMonitor</RootNamespace>
<AssemblyName>devenv</AssemblyName> <AssemblyName>devenv</AssemblyName>
<AssemblyVersion>1.0.24</AssemblyVersion> <AssemblyVersion>1.0.25</AssemblyVersion>
<Version>1.0.24</Version> <Version>1.0.25</Version>
<FileVersion>1.0.24</FileVersion> <FileVersion>1.0.25</FileVersion>
<InformationalVersion>1.0.24</InformationalVersion> <InformationalVersion>1.0.25</InformationalVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Costura.Fody" Version="6.0.0"> <PackageReference Include="Costura.Fody" Version="6.0.0">
@@ -1,5 +1,6 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Threading; using System.Threading;
namespace MonsterMonitor.Services namespace MonsterMonitor.Services
@@ -28,6 +29,10 @@ namespace MonsterMonitor.Services
_path = path; _path = path;
_arguments = arguments ?? string.Empty; _arguments = arguments ?? string.Empty;
_stopping = false; _stopping = false;
// Подчищаем ss.exe, оставшийся от предыдущей (аварийно закрытой) копии
// приложения — иначе его занятый порт не даст новому 3proxy стартовать,
// и watchdog будет бесконечно перезапускать мгновенно умирающий процесс.
KillOrphanedProcesses();
EnsureStarted(); EnsureStarted();
_watchdogTimer.Change(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10)); _watchdogTimer.Change(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10));
} }
@@ -58,6 +63,23 @@ namespace MonsterMonitor.Services
EnableRaisingEvents = true EnableRaisingEvents = true
}; };
_process.Start(); _process.Start();
// ss (3proxy) при занятом порту завершается почти мгновенно.
// Если процесс умер сразу после старта — не рапортуем «запущен» и не
// крутим бесконечный цикл рестартов, а один раз пишем понятную причину.
if (_process.WaitForExit(500))
{
var exitCode = SafeGetExitCode(_process);
var message = "Процесс ss завершился сразу после запуска (код " + exitCode +
"). Вероятно, локальный порт уже занят другим процессом ss.";
if (_lastStartError != message)
{
_lastStartError = message;
_log.Error(message);
}
return;
}
_lastStartError = null; _lastStartError = null;
_log.Info("Процесс ss запущен."); _log.Info("Процесс ss запущен.");
} }
@@ -134,6 +156,114 @@ namespace MonsterMonitor.Services
} }
} }
// Завершает «осиротевшие» экземпляры ss.exe, оставшиеся от прошлой копии
// приложения. Сопоставление по полному пути к исполняемому файлу, чтобы не
// задеть посторонние одноимённые процессы.
private void KillOrphanedProcesses()
{
string targetName;
string targetFullPath;
try
{
targetName = Path.GetFileNameWithoutExtension(_path);
targetFullPath = Path.GetFullPath(_path);
}
catch
{
return;
}
if (string.IsNullOrEmpty(targetName))
{
return;
}
var ownPid = _process != null && IsProcessRunning(_process) ? SafeGetId(_process) : -1;
Process[] candidates;
try
{
candidates = Process.GetProcessesByName(targetName);
}
catch (Exception ex)
{
_log.Warn("Не удалось перечислить процессы ss: " + ex.Message);
return;
}
foreach (var proc in candidates)
{
try
{
if (proc.Id == ownPid)
{
continue;
}
// Убиваем только процессы из нашего каталога ss.exe.
if (!PathsEqual(SafeGetProcessPath(proc), targetFullPath))
{
continue;
}
proc.Kill();
proc.WaitForExit(3000);
_log.Warn("Завершен осиротевший процесс ss (PID " + proc.Id + ") от предыдущего запуска.");
}
catch (Exception ex)
{
_log.Warn("Не удалось завершить осиротевший ss: " + ex.Message);
}
finally
{
proc.Dispose();
}
}
}
private static bool PathsEqual(string a, string b)
{
return !string.IsNullOrEmpty(a) && !string.IsNullOrEmpty(b) &&
string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
}
private static string SafeGetProcessPath(Process process)
{
try
{
return process.MainModule?.FileName;
}
catch
{
// Доступ к MainModule может быть запрещён (другой пользователь/разрядность).
return null;
}
}
private static int SafeGetId(Process process)
{
try
{
return process.Id;
}
catch
{
return -1;
}
}
private static int SafeGetExitCode(Process process)
{
try
{
return process.ExitCode;
}
catch
{
return -1;
}
}
public void Dispose() public void Dispose()
{ {
Stop(); Stop();