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

如何筛选特定应用/镜像名的活跃TCP连接?Linq Where语句写法

解决方法:筛选特定镜像名/应用的TCP连接

嘿,我来帮你搞定这个问题!你现在遇到的核心点是:IPGlobalProperties.GetActiveTcpConnections()返回的TcpConnectionInformation对象只包含TCP连接的地址和端口信息,没有直接关联进程或镜像名。所以我们需要先把这些连接和对应的进程信息绑定起来,再做筛选。

整体思路

  1. 调用Windows原生API GetExtendedTcpTable 获取包含进程ID(PID)的完整TCP连接列表。
  2. 将这个列表和GetActiveTcpConnections()的结果关联,得到每个TCP连接对应的进程ID和镜像名。
  3. 用Linq的Where()方法根据镜像名、PID或应用名筛选目标连接。

完整代码实现

第一步:定义所需的结构体和原生API调用

这些代码用来获取带PID的TCP连接表:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;

// 存储带进程信息的TCP连接条目
public class TcpEntry
{
    public IPAddress LocalAddress { get; set; }
    public int LocalPort { get; set; }
    public IPAddress RemoteAddress { get; set; }
    public int RemotePort { get; set; }
    public int ProcessId { get; set; }
}

// 存储TCP连接+进程完整信息的类
public class TcpConnectionWithProcess
{
    public TcpConnectionInformation Connection { get; set; }
    public int ProcessId { get; set; }
    public string ImageName { get; set; } // 和资源监视器的"镜像名"一致
}

// Windows原生API相关定义
[StructLayout(LayoutKind.Sequential)]
internal struct MIB_TCPROW_OWNER_PID
{
    public uint State;
    public uint LocalAddr;
    public uint LocalPort;
    public uint RemoteAddr;
    public uint RemotePort;
    public uint ProcessId;
}

[StructLayout(LayoutKind.Sequential)]
internal struct MIB_TCPTABLE_OWNER_PID
{
    public uint NumEntries;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public MIB_TCPROW_OWNER_PID[] Table;
}

internal static class NativeIpHelper
{
    [DllImport("iphlpapi.dll", SetLastError = true)]
    public static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref uint pdwSize, bool bOrder, int ulAf, uint TableClass, uint Reserved);

    // 将uint格式的IP地址转换为IPAddress对象
    public static IPAddress UintToIpAddress(uint ipUint)
    {
        var bytes = BitConverter.GetBytes(ipUint);
        Array.Reverse(bytes);
        return new IPAddress(bytes);
    }

    // 将网络字节序的端口转换为主机字节序的int值
    public static int UintToPort(uint portUint)
    {
        return (int)IPAddress.NetworkToHostOrder((short)portUint);
    }
}

第二步:编写获取带进程信息的TCP连接列表的方法

public static List<TcpConnectionWithProcess> GetActiveTcpConnectionsWithProcessInfo()
{
    var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
    var tcpConnections = ipProperties.GetActiveTcpConnections();
    var tcpEntriesWithPid = GetTcpEntriesWithPid();

    var result = new List<TcpConnectionWithProcess>();

    foreach (var connection in tcpConnections)
    {
        // 在带PID的列表中匹配当前连接
        var matchingEntry = tcpEntriesWithPid.FirstOrDefault(entry =>
            entry.LocalAddress.Equals(connection.LocalEndPoint.Address) &&
            entry.LocalPort == connection.LocalEndPoint.Port &&
            entry.RemoteAddress.Equals(connection.RemoteEndPoint.Address) &&
            entry.RemotePort == connection.RemoteEndPoint.Port);

        if (matchingEntry == null) continue;

        try
        {
            var process = Process.GetProcessById(matchingEntry.ProcessId);
            // 获取镜像名(和资源监视器一致,比如"chrome.exe")
            var imageName = Path.GetFileName(process.MainModule.FileName);

            result.Add(new TcpConnectionWithProcess
            {
                Connection = connection,
                ProcessId = matchingEntry.ProcessId,
                ImageName = imageName
            });
        }
        catch (ArgumentException)
        {
            // 进程可能已经退出,跳过该连接
            continue;
        }
        catch (InvalidOperationException)
        {
            // 无权限访问进程(比如系统进程),跳过
            continue;
        }
    }

    return result;
}

private static List<TcpEntry> GetTcpEntriesWithPid()
{
    var entries = new List<TcpEntry>();
    uint bufferSize = 0;

    // 先调用一次获取所需的缓冲区大小
    NativeIpHelper.GetExtendedTcpTable(IntPtr.Zero, ref bufferSize, false, 2, 5, 0);
    IntPtr tcpTablePtr = Marshal.AllocHGlobal((int)bufferSize);

    try
    {
        var retCode = NativeIpHelper.GetExtendedTcpTable(tcpTablePtr, ref bufferSize, false, 2, 5, 0);
        if (retCode != 0) return entries;

        // 解析TCP表内容
        var tcpTable = (MIB_TCPTABLE_OWNER_PID)Marshal.PtrToStructure(tcpTablePtr, typeof(MIB_TCPTABLE_OWNER_PID));
        var tableRows = new MIB_TCPROW_OWNER_PID[tcpTable.NumEntries];
        IntPtr rowPtr = (IntPtr)((long)tcpTablePtr + Marshal.SizeOf(tcpTable.NumEntries));

        for (int i = 0; i < tcpTable.NumEntries; i++)
        {
            tableRows[i] = (MIB_TCPROW_OWNER_PID)Marshal.PtrToStructure(rowPtr, typeof(MIB_TCPROW_OWNER_PID));
            rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(typeof(MIB_TCPROW_OWNER_PID)));

            entries.Add(new TcpEntry
            {
                LocalAddress = NativeIpHelper.UintToIpAddress(tableRows[i].LocalAddr),
                LocalPort = NativeIpHelper.UintToPort(tableRows[i].LocalPort),
                RemoteAddress = NativeIpHelper.UintToIpAddress(tableRows[i].RemoteAddr),
                RemotePort = NativeIpHelper.UintToPort(tableRows[i].RemotePort),
                ProcessId = (int)tableRows[i].ProcessId
            });
        }
    }
    finally
    {
        Marshal.FreeHGlobal(tcpTablePtr);
    }

    return entries;
}

第三步:筛选目标连接

现在你可以用Linq轻松筛选了:

1. 按镜像名筛选(比如筛选Chrome的连接)

var allConnectionsWithProcess = GetActiveTcpConnectionsWithProcessInfo();
var chromeConnections = allConnectionsWithProcess
    .Where(c => c.ImageName.Equals("chrome.exe", StringComparison.OrdinalIgnoreCase))
    .Select(c => c.Connection)
    .ToList();

2. 按进程ID筛选

var targetPid = 12345; // 替换为你的目标进程ID
var targetConnections = allConnectionsWithProcess
    .Where(c => c.ProcessId == targetPid)
    .Select(c => c.Connection)
    .ToList();

3. 按应用名(进程名)筛选

如果不需要完整的镜像名(比如只需要"chrome"而不是"chrome.exe"),可以用ProcessName:

var edgeConnections = allConnectionsWithProcess
    .Where(c => 
    {
        try { return Process.GetProcessById(c.ProcessId).ProcessName.Equals("msedge", StringComparison.OrdinalIgnoreCase); }
        catch { return false; }
    })
    .Select(c => c.Connection)
    .ToList();

注意事项

  • 管理员权限:获取系统进程的TCP连接需要管理员权限,否则会跳过无权限访问的进程。
  • 进程生命周期:如果在获取信息的过程中进程退出,会抛出异常,代码中已经做了捕获处理。
  • 镜像名准确性:用Path.GetFileName(process.MainModule.FileName)获取的镜像名和Windows资源监视器中的完全一致,比ProcessName更准确。

内容的提问来源于stack exchange,提问作者is_oz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:07:34