You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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); // 出错后仍等待,避免频繁报错
        }
    }
}

修正点说明

  1. 修复了取消逻辑:按钮判断改为线程忙碌时才取消,循环里检查CancellationPending来终止循环。
  2. 添加了Thread.Sleep(interval)控制轮询间隔,降低CPU占用。
  3. 使用HashSet记录已输出的连接,避免重复打印,同时收集所有新连接后通过ReportProgress批量更新UI,减少Invoke次数。
  4. 添加了异常捕获,避免程序崩溃,同时通过ProgressChanged事件通知UI错误信息。
  5. 修正了参数传递的问题,正确获取传入的间隔时间。

部署为Windows服务的优化方案

BackgroundWorker是WinForm专属组件,不能在Windows服务中使用,建议改用以下方案:

核心实现思路

  1. 使用Task配合CancellationToken实现可取消的后台任务,替代BackgroundWorker。
  2. 移除所有UI相关代码,改为将连接信息写入日志文件、数据库或通过其他方式输出(服务没有UI界面)。
  3. 确保服务运行在管理员权限下,因为GetActiveTcpConnections需要系统级权限才能正常调用。
  4. 使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 03:05:41