diff --git a/SocketExample/LoginWindow.xaml b/SocketExample/LoginWindow.xaml
new file mode 100644
index 0000000..9d444d6
--- /dev/null
+++ b/SocketExample/LoginWindow.xaml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SocketExample/LoginWindow.xaml.cs b/SocketExample/LoginWindow.xaml.cs
new file mode 100644
index 0000000..f5630d1
--- /dev/null
+++ b/SocketExample/LoginWindow.xaml.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace SocketExample
+{
+ ///
+ /// LoginWindow.xaml 的交互逻辑
+ ///
+ public partial class LoginWindow : Window
+ {
+ // 定义事件
+ public event Action LoginSuccess;
+ public event Action LoginFailed;
+
+ // 最大尝试次数
+ private const int MAX_ATTEMPTS = 2;
+
+ // 当前尝试次数
+ private int _attemptCount = 0;
+
+ // 正确的用户名和密码(实际应用中应从数据库或配置中读取)
+ private const string CORRECT_USERNAME = "haiweiadmin";
+ private const string CORRECT_PASSWORD = "haiweinb123";
+
+ public LoginWindow()
+ {
+ InitializeComponent();
+ UpdateAttemptsDisplay();
+
+ // 设置焦点到用户名输入框
+ txtUsername.Focus();
+
+ // 绑定回车键事件
+ txtPassword.KeyDown += OnPasswordKeyDown;
+ }
+
+ private void OnPasswordKeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.Key == Key.Enter)
+ {
+ AttemptLogin();
+ }
+ }
+
+ private void btnLogin_Click(object sender, RoutedEventArgs e)
+ {
+ AttemptLogin();
+ }
+
+ private void btnCancel_Click(object sender, RoutedEventArgs e)
+ {
+ // 取消登录,关闭程序
+ LoginFailed?.Invoke();
+ this.Close();
+ }
+
+ private void AttemptLogin()
+ {
+ string username = txtUsername.Text.Trim();
+ string password = txtPassword.Password;
+
+ // 验证输入
+ if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
+ {
+ ShowError("用户名和密码不能为空!");
+ return;
+ }
+
+ // 验证用户名和密码
+ if (username == CORRECT_USERNAME && password == CORRECT_PASSWORD)
+ {
+ // 登录成功
+ LoginSuccess?.Invoke();
+ this.Close();
+ }
+ else
+ {
+ // 登录失败
+ _attemptCount++;
+ UpdateAttemptsDisplay();
+
+ if (_attemptCount >= MAX_ATTEMPTS)
+ {
+ // 超过最大尝试次数
+ MessageBox.Show($"登录失败超过{MAX_ATTEMPTS}次,程序即将关闭!",
+ "登录失败",
+ MessageBoxButton.OK,
+ MessageBoxImage.Error);
+
+ LoginFailed?.Invoke();
+ this.Close();
+ }
+ else
+ {
+ ShowError($"用户名或密码错误!剩余尝试次数:{MAX_ATTEMPTS - _attemptCount}");
+ txtPassword.Password = "";
+ txtPassword.Focus();
+ }
+ }
+ }
+
+ private void ShowError(string message)
+ {
+ lblError.Text = message;
+ lblError.Visibility = Visibility.Visible;
+ }
+
+ private void UpdateAttemptsDisplay()
+ {
+ int remainingAttempts = MAX_ATTEMPTS - _attemptCount;
+ lblAttempts.Text = remainingAttempts > 0
+ ? $"剩余尝试次数:{remainingAttempts}"
+ : "已超过最大尝试次数";
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ base.OnClosed(e);
+
+ // 清理事件绑定
+ txtPassword.KeyDown -= OnPasswordKeyDown;
+ }
+ }
+}
diff --git a/SocketExample/MemoryManager.cs b/SocketExample/MemoryManager.cs
new file mode 100644
index 0000000..8fe1890
--- /dev/null
+++ b/SocketExample/MemoryManager.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SocketExample
+{
+ public static class MemoryManager
+ {
+ private static readonly object _lock = new object();
+ private static DateTime _lastCleanupTime = DateTime.MinValue;
+ private static Timer _cleanupTimer;
+
+ ///
+ /// 初始化内存管理器
+ ///
+ /// 清理间隔(分钟)
+ public static void Initialize(int cleanupIntervalMinutes = 5)
+ {
+ // 创建定时清理任务
+ _cleanupTimer = new Timer(CleanupCallback, null,
+ TimeSpan.FromMinutes(cleanupIntervalMinutes),
+ TimeSpan.FromMinutes(cleanupIntervalMinutes));
+
+ Console.WriteLine($"MemoryManager已启动,每{cleanupIntervalMinutes}分钟检查一次内存");
+ }
+
+ ///
+ /// 立即清理内存
+ ///
+ /// 是否激进清理(包括第2代)
+ public static void ForceCleanup(bool aggressive = false)
+ {
+ lock (_lock)
+ {
+ try
+ {
+ long before = GC.GetTotalMemory(true);
+ Console.WriteLine($"清理前内存: {FormatBytes(before)}");
+
+ if (aggressive)
+ {
+ // 激进模式:清理所有代
+ GC.Collect(2, GCCollectionMode.Forced);
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+ }
+ else
+ {
+ // 温和模式:只清理第0代和第1代
+ GC.Collect(0, GCCollectionMode.Optimized);
+ GC.Collect(1, GCCollectionMode.Optimized);
+ }
+
+ long after = GC.GetTotalMemory(true);
+ Console.WriteLine($"清理后内存: {FormatBytes(after)}");
+ Console.WriteLine($"释放了: {FormatBytes(before - after)}");
+
+ _lastCleanupTime = DateTime.Now;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"内存清理失败: {ex.Message}");
+ }
+ }
+ }
+
+ ///
+ /// 智能清理 - 根据内存使用情况决定清理策略
+ ///
+ public static void SmartCleanup()
+ {
+ var memoryInfo = GetMemoryInfo();
+
+ Console.WriteLine($"当前内存使用: {memoryInfo.UsagePercentage:F1}% ({memoryInfo.ProcessMemoryMB:F1}MB)");
+
+ if (memoryInfo.UsagePercentage > 85)
+ {
+ Console.WriteLine("内存使用超过85%,执行深度清理...");
+ ForceCleanup(true); // 激进清理
+ }
+ else if (memoryInfo.UsagePercentage > 70)
+ {
+ Console.WriteLine("内存使用超过70%,执行普通清理...");
+ ForceCleanup(false); // 普通清理
+ }
+ else if (memoryInfo.UsagePercentage > 50 &&
+ DateTime.Now - _lastCleanupTime > TimeSpan.FromMinutes(10))
+ {
+ Console.WriteLine("内存使用较高且超过10分钟未清理,执行轻度清理...");
+ ForceCleanup(false);
+ }
+ else
+ {
+ Console.WriteLine("内存使用正常,跳过清理");
+ }
+ }
+
+ ///
+ /// 获取内存信息
+ ///
+ public static MemoryInfo GetMemoryInfo()
+ {
+ var process = Process.GetCurrentProcess();
+ process.Refresh();
+
+ long processMemory = process.WorkingSet64;
+ //long totalPhysicalMemory = GetTotalPhysicalMemory();
+
+ return new MemoryInfo
+ {
+ ProcessMemoryBytes = processMemory,
+ ProcessMemoryMB = processMemory / 1024.0 / 1024.0,
+ Gen0Collections = GC.CollectionCount(0),
+ Gen1Collections = GC.CollectionCount(1),
+ Gen2Collections = GC.CollectionCount(2)
+ };
+ }
+
+ ///
+ /// 监控内存使用,超过阈值自动清理
+ ///
+ public static void StartMonitoring(int thresholdMB = 100, int checkIntervalSeconds = 30)
+ {
+ Task.Run(async () =>
+ {
+ while (true)
+ {
+ await Task.Delay(TimeSpan.FromSeconds(checkIntervalSeconds));
+
+ var info = GetMemoryInfo();
+
+ if (info.ProcessMemoryMB > thresholdMB)
+ {
+ Console.WriteLine($"内存使用超过{thresholdMB}MB,当前{info.ProcessMemoryMB:F1}MB,触发自动清理...");
+ SmartCleanup();
+ }
+ }
+ });
+ }
+
+ private static void CleanupCallback(object state)
+ {
+ Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 定时内存检查...");
+ SmartCleanup();
+ }
+
+ private static string FormatBytes(long bytes)
+ {
+ string[] suffixes = { "B", "KB", "MB", "GB" };
+ int suffixIndex = 0;
+ double number = bytes;
+
+ while (number >= 1024 && suffixIndex < suffixes.Length - 1)
+ {
+ number /= 1024;
+ suffixIndex++;
+ }
+
+ return $"{number:F2} {suffixes[suffixIndex]}";
+ }
+
+ public class MemoryInfo
+ {
+ public long ProcessMemoryBytes { get; set; }
+ public double ProcessMemoryMB { get; set; }
+ public long TotalPhysicalMemoryBytes { get; set; }
+ public double TotalPhysicalMemoryMB { get; set; }
+ public double UsagePercentage { get; set; }
+ public int Gen0Collections { get; set; }
+ public int Gen1Collections { get; set; }
+ public int Gen2Collections { get; set; }
+ }
+ }
+}
diff --git a/SocketExample/PanelItem.cs b/SocketExample/PanelItem.cs
index c04db70..15727a2 100644
--- a/SocketExample/PanelItem.cs
+++ b/SocketExample/PanelItem.cs
@@ -1,4 +1,5 @@
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
@@ -38,6 +39,7 @@ public partial class TCPWindowV2
public string Text { get; set; }//客户端编号
public string IPtext { get; set; }//IP文本框
public string Porttext { get; set; }//端口文本框
+ public int Tagcleancount { get; set; }//内存清理计数
private string _messagetext;
public string SessionID { get; set; }
@@ -179,6 +181,7 @@ public partial class TCPWindowV2
LinkState = "未连接";
IPtext_ReadOnly = false;
Porttext_ReadOnly = false;
+ Tagcleancount = 0;
PanelInitialization();
}
@@ -192,6 +195,7 @@ public partial class TCPWindowV2
LinkButtonText = "断开";
StateColour = "Green";
LinkState = "已连接";
+ Tagcleancount = 0;
IPtext_ReadOnly = true;
Porttext_ReadOnly = true;
PanelInitialization();
@@ -201,13 +205,10 @@ public partial class TCPWindowV2
sendcomn = new LinkCommand(SessionButton_Click_Send);
sendactioncomn = new LinkCommand(SessionButton_SendActionComn);
GPOSelectionChangedCommand = new RelayCommand(SessionGPOComboBox_SelectChanged);
- Thread thread = new Thread(() => //连接初始化线程防止卡住UI线程
+ Task.Run(() =>
{
-
SessionClientConnected(TcpSessionClient);
-
- });
- thread.Start();
+ });//连接初始化线程防止卡住UI线程
}
public void PanelInitialization()//终端初始化
@@ -273,7 +274,7 @@ public partial class TCPWindowV2
#region socket事件
- private Task onRecieved(ITcpClient client, ReceivedDataEventArgs e) //接收事件
+ private Task OnRecieved(ITcpClient client, ReceivedDataEventArgs e) //接收事件
{
ClientRecieved(e);
return EasyTask.CompletedTask;
@@ -310,26 +311,33 @@ public partial class TCPWindowV2
Array.Copy(data, 5, newData, 5, 4);
Array.Copy(data, 5, newData, 6, data.Length - 5);
Timeinfo = $"{time}";//获取时间
-
+ string year = DateTime.Now.ToString("yyyy-MM-dd");
+ path = $"日志文件夹/{year}/{Text}/" + Text + "标签(" + IPtext + ")" + ".txt";
//Infotext += $"({currentTime})客户端接收到EPC信息:\n{EPCASC}\n\n";
-
List taglist = GetTagInfos(newData);
- ObservableCollection items = new ObservableCollection();
+ ObservableCollection items = new ObservableCollection();
+ EnsureFolderExists($"日志文件夹/{year}/{Text}");
+ EnsureTxtExists(path, Text, IPtext, Porttext);
+ var batch = new List();
for (int j = 0; j < taglist.Count; j++)
{
EPCinfo = BitConverter.ToString(taglist[j].EPC).Replace("-", "");
items.Add(new TagItem(hexString, taglist[j].EPCstring, EPCinfo, taglist[j].RSSI.ToString(), taglist[j].Count.ToString(), Timeinfo));
- string year = DateTime.Now.ToString("yyyy-MM-dd");
- EnsureFolderExists($"日志文件夹/{year}/{Text}");
- path = $"日志文件夹/{year}/{Text}/" + Text + "标签(" + IPtext + ")" + ".txt";
- EnsureTxtExists(path, Text, IPtext, Porttext);
- writeToTxt(path, $"接收消息:{hexString}\nEPC:{taglist[j].EPCstring}\nHEX:{EPCinfo}\nRSSI:{taglist[j].RSSI.ToString()} Count:{taglist[j].Count.ToString()} Time:{Timeinfo}\n____________________________");
- path = "";
-
+ batch.Add($"接收消息:{hexString}\nEPC:{taglist[j].EPCstring}\nHEX:{EPCinfo}\nRSSI:{taglist[j].RSSI.ToString()} Count:{taglist[j].Count.ToString()} Time:{Timeinfo}\n____________________________");
+ //writeToTxt(path, $"接收消息:{hexString}\nEPC:{taglist[j].EPCstring}\nHEX:{EPCinfo}\nRSSI:{taglist[j].RSSI.ToString()} Count:{taglist[j].Count.ToString()} Time:{Timeinfo}\n____________________________");
//LogService.Instance.Debug("");
}
-
+ Tagcleancount++;
+ if (Tagcleancount > 10) // 一次性处理大量标签时
+ {
+ //Task.Run(() => System.Windows.MemoryManager.TryCleanupMemory());
+ Tagcleancount = 0;
+ }
+ writeListToTxt(path,batch);
+ path = "";
+ batch.Clear();
TagItems = items;
+ //items.Clear();
}
catch (Exception ex)
{
@@ -346,22 +354,23 @@ public partial class TCPWindowV2
List taglist = GetTagInfos(data);
ObservableCollection items = new ObservableCollection();
+ string year = DateTime.Now.ToString("yyyy-MM-dd");
+ EnsureFolderExists($"日志文件夹/{year}/{Text}");
+ path = $"日志文件夹/{year}/{Text}/" + Text + "标签(" + IPtext + ")" + ".txt";
+ EnsureTxtExists(path, Text, IPtext, Porttext);
+ var batch = new List();
for (int j = 0; j < taglist.Count; j++)
{
EPCinfo = BitConverter.ToString(taglist[j].EPC).Replace("-", "");
items.Add(new TagItem(hexString, taglist[j].EPCstring, EPCinfo, taglist[j].RSSI.ToString(), taglist[j].Count.ToString(), Timeinfo));
- string year = DateTime.Now.ToString("yyyy-MM-dd");
- EnsureFolderExists($"日志文件夹/{year}/{Text}");
- path = $"日志文件夹/{year}/{Text}/" + Text + "标签(" + IPtext + ")" + ".txt";
- EnsureTxtExists(path, Text, IPtext, Porttext);
- writeToTxt(path, $"接收消息:{hexString}\nEPC:{taglist[j].EPCstring}\nHEX:{EPCinfo}\nRSSI:{taglist[j].RSSI.ToString()} Count:{taglist[j].Count.ToString()} Time:{Timeinfo}\n____________________________");
- path = "";
-
+ batch.Add($"接收消息:{hexString}\nEPC:{taglist[j].EPCstring}\nHEX:{EPCinfo}\nRSSI:{taglist[j].RSSI.ToString()} Count:{taglist[j].Count.ToString()} Time:{Timeinfo}\n____________________________");
+ //writeToTxt(path, $"接收消息:{hexString}\nEPC:{taglist[j].EPCstring}\nHEX:{EPCinfo}\nRSSI:{taglist[j].RSSI.ToString()} Count:{taglist[j].Count.ToString()} Time:{Timeinfo}\n____________________________");
//LogService.Instance.Debug("");
}
-
+ writeListToTxt(path, batch);
+ path = "";
+ batch.Clear();
TagItems = items;
-
}
catch (Exception ex)
{
@@ -588,10 +597,10 @@ public partial class TCPWindowV2
}
}
- private Task onConnected(ITcpClient client, ConnectedEventArgs e)//连接后初始化
+ private Task OnConnected(ITcpClient client, ConnectedEventArgs e)//连接后初始化
{
ClientConnected(client);
-
+ LinkButtonText = "断开";
return EasyTask.CompletedTask;
}
@@ -783,6 +792,16 @@ public partial class TCPWindowV2
streamWriter.Close();
}
+ private static void writeListToTxt(string path, List content)
+ {
+ StreamWriter streamWriter = new StreamWriter(path, true);
+ foreach (var line in content)
+ {
+ streamWriter.WriteLineAsync(line);
+ }
+ streamWriter.Close();
+ }
+
#endregion
#region 动态界面控件功能
@@ -799,11 +818,11 @@ public partial class TCPWindowV2
client = new TcpClient();
//连接事件
- client.Connected += onConnected;
+ client.Connected += OnConnected;
//断连事件
client.Closed = (client, e) => { try { GPIOthread.Abort(); Infotext += "已断开!\n"; StateColour = "Red"; LinkState = "未连接"; } catch (Exception ex) { Infotext += ex; } return EasyTask.CompletedTask; };
//接收事件
- client.Received += onRecieved;
+ client.Received += OnRecieved;
//设置连接属性
await client.SetupAsync(new TouchSocketConfig().SetRemoteIPHost($"{IPtext}:{Porttext}").ConfigureContainer(a =>
@@ -818,7 +837,7 @@ public partial class TCPWindowV2
{
Infotext += $"处理请求时出错: {ex.Message}\n";
}
- LinkButtonText = "断开";
+
}
else
{
diff --git a/SocketExample/RFIDmonitor.csproj b/SocketExample/RFIDmonitor.csproj
index 6df2470..3016a27 100644
--- a/SocketExample/RFIDmonitor.csproj
+++ b/SocketExample/RFIDmonitor.csproj
@@ -171,6 +171,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
@@ -185,6 +189,9 @@
ClientWindow.xaml
+
+ LoginWindow.xaml
+
MainWindow.xaml
Code
@@ -207,6 +214,7 @@
+
diff --git a/SocketExample/TCPWindowV2.xaml.cs b/SocketExample/TCPWindowV2.xaml.cs
index 619e3cd..9909faa 100644
--- a/SocketExample/TCPWindowV2.xaml.cs
+++ b/SocketExample/TCPWindowV2.xaml.cs
@@ -77,6 +77,11 @@ namespace SocketExample
PanelContainer.ItemsSource = items;
SaveWindowSettings();
Buttonflag = 0;
+ MemoryManager.Initialize(10); // 每10分钟自动清理
+ MemoryManager.StartMonitoring(200, 60); // 超过200MB时自动清理
+ LoginWindow loginWindow = new LoginWindow();
+ loginWindow.LoginFailed += OnLoginFailed;
+ //loginWindow.ShowDialog();
}
#endregion
//结束所有线程,防止心跳线程冗余
@@ -85,9 +90,17 @@ namespace SocketExample
System.Environment.Exit(0);
}
+ private void OnLoginFailed()
+ {
+ // 登录失败,关闭程序
+ Application.Current.Shutdown();
+ }
+
#region 主界面按钮事件
private void GenerateButton_Click(object sender, RoutedEventArgs e)//添加客户端框体
{
+ LoginWindow loginWindow = new LoginWindow();//启用密码验证
+ //loginWindow.ShowDialog();
if (int.TryParse(CountTextBox.Text, out int count) && count > 0)
{
//var items = new List();
@@ -151,6 +164,8 @@ namespace SocketExample
}
private void ListenButton_Click(object sender, RoutedEventArgs e)
{
+ LoginWindow loginWindow = new LoginWindow(); //启用密码验证
+ loginWindow.ShowDialog();
Thread ListeningPortThread = new Thread(ListeningTheard);
ListeningPortThread.IsBackground = true;
ListeningPortThread.Start();