使用GetActiveTcpConnections与BackgroundWorker检测连接的安全性及优化咨询
问题分析与优化方案
你的代码能运行,但存在几个影响稳定性和性能的问题,同时针对最终部署为服务的目标,也需要调整实现方式,下面逐一说明:
现有代码的核心问题
- 取消逻辑完全失效:
button2_Click里判断写反了,应该是if (backgroundWorker1.IsBusy)才调用CancelAsync,现在的逻辑是线程没在运行时才尝试取消,完全没用。BackgroundProcessLogicMethod的死循环里没有检查bw.CancellationPending,就算调用了CancelAsync,线程也会一直跑下去,无法终止。
- CPU占用过高:无限循环里没有任何延迟,线程会持续占用CPU核心,导致系统资源浪费。
- UI操作效率低下:每匹配到一个连接就调用一次
Invoke频繁更新UI,会造成UI线程频繁被唤醒,影响界面响应。 - 未处理异常:
GetActiveTcpConnections可能因权限不足、系统状态变化抛出异常,后台线程未捕获的话会直接导致程序崩溃。 - 参数传递错误:
DoWork方法里直接使用未定义的arg变量,应该从e.Argument获取传入的间隔时间。
修正后的WinForm测试代码
private void button1_Click(object sender, EventArgs e) { if (!backgroundWorker1.IsBusy) { backgroundWorker1.WorkerSupportsCancellation = true; backgroundWorker1.RunWorkerAsync(2000); // 传入2秒间隔 MessageBox.Show("后台线程已启动"); } } private void button2_Click(object sender, EventArgs e) { if (backgroundWorker1.IsBusy) { backgroundWorker1.CancelAsync(); MessageBox.Show("已发送终止请求"); } } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker helperBW = sender as BackgroundWorker; int interval = (int)e.Argument; // 获取间隔时间 try { BackgroundProcessLogicMethod(helperBW, interval); } catch (Exception ex) { // 捕获异常,可记录日志或通过ReportProgress通知UI helperBW.ReportProgress(0, $"发生错误: {ex.Message}"); } } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // 统一更新UI richTextBox1.AppendText(e.UserState.ToString() + "\n\r"); } private void BackgroundProcessLogicMethod(BackgroundWorker bw, int interval) { HashSet<string> recordedConnections = new HashSet<string>(); // 记录已输出的连接,避免重复打印 while (!bw.CancellationPending) { try { IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties(); TcpConnectionInformation[] connections = properties.GetActiveTcpConnections(); List<string> newConnections = new List<string>(); foreach (TcpConnectionInformation c in connections) { string endpoint = c.RemoteEndPoint.ToString(); if (endpoint == "192.168.4.14:443" && !recordedConnections.Contains(endpoint)) { newConnections.Add(endpoint); recordedConnections.Add(endpoint); } } // 批量更新UI if (newConnections.Count > 0) { bw.ReportProgress(0, string.Join("\n\r", newConnections)); } // 等待指定间隔,同时响应取消请求 Thread.Sleep(interval); } catch (Exception ex) { bw.ReportProgress(0, $"轮询出错: {ex.Message}"); Thread.Sleep(interval); // 出错后仍等待,避免频繁报错 } } }
修正点说明
- 修复了取消逻辑:按钮判断改为线程忙碌时才取消,循环里检查
CancellationPending来终止循环。 - 添加了
Thread.Sleep(interval)控制轮询间隔,降低CPU占用。 - 使用
HashSet记录已输出的连接,避免重复打印,同时收集所有新连接后通过ReportProgress批量更新UI,减少Invoke次数。 - 添加了异常捕获,避免程序崩溃,同时通过
ProgressChanged事件通知UI错误信息。 - 修正了参数传递的问题,正确获取传入的间隔时间。
部署为Windows服务的优化方案
BackgroundWorker是WinForm专属组件,不能在Windows服务中使用,建议改用以下方案:
核心实现思路
- 使用
Task配合CancellationToken实现可取消的后台任务,替代BackgroundWorker。 - 移除所有UI相关代码,改为将连接信息写入日志文件、数据库或通过其他方式输出(服务没有UI界面)。
- 确保服务运行在管理员权限下,因为
GetActiveTcpConnections需要系统级权限才能正常调用。 - 使用
Timer或Task.Delay控制轮询间隔,避免CPU占用过高。
简化的服务核心代码示例
public partial class TcpMonitorService : ServiceBase { private CancellationTokenSource _cts; private Task _monitorTask; private readonly int _pollInterval = 2000; private HashSet<string> _recordedConnections = new HashSet<string>(); private readonly string _logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tcp_connections.log"); public TcpMonitorService() { InitializeComponent(); } protected override void OnStart(string[] args) { _cts = new CancellationTokenSource(); _monitorTask = Task.Run(() => MonitorTcpConnections(_cts.Token), _cts.Token); WriteLog("TCP连接监控服务已启动"); } protected override void OnStop() { _cts.Cancel(); _monitorTask.Wait(); WriteLog("TCP连接监控服务已停止"); } private void MonitorTcpConnections(CancellationToken token) { while (!token.IsCancellationRequested) { try { IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties(); TcpConnectionInformation[] connections = properties.GetActiveTcpConnections(); foreach (TcpConnectionInformation c in connections) { string endpoint = c.RemoteEndPoint.ToString(); if (endpoint == "192.168.4.14:443" && !_recordedConnections.Contains(endpoint)) { WriteLog($"发现新连接: {endpoint}"); _recordedConnections.Add(endpoint); } } Task.Delay(_pollInterval, token).Wait(); // 等待间隔,响应取消请求 } catch (OperationCanceledException) { // 任务被取消,退出循环 break; } catch (Exception ex) { WriteLog($"监控出错: {ex.Message}"); Task.Delay(_pollInterval, token).Wait(); } } } private void WriteLog(string message) { string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}\n"; File.AppendAllText(_logPath, logEntry); } }
服务部署注意事项
- 创建Windows服务项目时,需添加安装程序,设置服务的启动类型(自动/手动)。
- 安装服务时,使用管理员权限运行
installutil.exe工具。 - 如果需要远程管理服务,可以添加WCF或REST接口,或者使用Windows事件日志替代文件日志,方便查看运行状态。
内容的提问来源于stack exchange,提问作者incubi
相关产品推荐
相关产品推荐

