.NET中如何获取进程正在监听的端口?
纯.NET代码获取进程监听端口的方案
当然可以用纯.NET类库实现,不需要调用PowerShell命令解析输出,以下是两种可行的方案:
方案一:使用System.Net.NetworkInformation命名空间
.NET自带的IPGlobalProperties类可以获取系统的TCP连接信息,结合Process类就能关联到对应的进程监听端口:
using System; using System.Diagnostics; using System.Net.NetworkInformation; class Program { static void Main() { // 获取系统所有TCP连接信息 IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties(); TcpConnectionInformation[] tcpConnections = properties.GetActiveTcpConnections(); foreach (var conn in tcpConnections) { // 筛选处于监听状态的连接 if (conn.State == TcpState.Listen) { try { // 通过进程ID获取进程实例 Process process = Process.GetProcessById(conn.OwningProcess); Console.WriteLine($"进程名: {process.ProcessName}, 监听端口: {conn.LocalEndPoint.Port}, PID: {conn.OwningProcess}"); } catch (ArgumentException) { // 进程可能已退出,直接输出端口信息 Console.WriteLine($"PID: {conn.OwningProcess} 对应的进程已不存在,监听端口: {conn.LocalEndPoint.Port}"); } } } } }
注意:该方法需要以管理员权限运行程序,否则可能无法获取部分进程的端口关联信息。
方案二:通过P/Invoke调用Windows API
如果需要更底层的控制或兼容更多场景(比如UDP监听),可以直接调用Windows原生的GetExtendedTcpTable API实现:
using System; using System.Diagnostics; using System.Net; using System.Runtime.InteropServices; class TcpPortHelper { [StructLayout(LayoutKind.Sequential)] private struct MIB_TCPTABLE_OWNER_PID { public uint dwNumEntries; [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)] public MIB_TCPROW_OWNER_PID[] table; } [StructLayout(LayoutKind.Sequential)] private struct MIB_TCPROW_OWNER_PID { public uint dwState; public uint dwLocalAddr; public uint dwLocalPort; public uint dwRemoteAddr; public uint dwRemotePort; public uint dwOwningPid; } [DllImport("iphlpapi.dll", SetLastError = true)] private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref uint pdwSize, bool bOrder, uint ulAf, uint TableClass, uint Reserved); public static void GetAllTcpListenerProcesses() { uint bufferSize = 0; // 先调用一次获取所需内存大小 GetExtendedTcpTable(IntPtr.Zero, ref bufferSize, true, 2, 5, 0); IntPtr tcpTablePtr = Marshal.AllocHGlobal((int)bufferSize); try { uint result = GetExtendedTcpTable(tcpTablePtr, ref bufferSize, true, 2, 5, 0); if (result != 0) return; MIB_TCPTABLE_OWNER_PID tcpTable = Marshal.PtrToStructure<MIB_TCPTABLE_OWNER_PID>(tcpTablePtr); MIB_TCPROW_OWNER_PID[] rows = new MIB_TCPROW_OWNER_PID[tcpTable.dwNumEntries]; IntPtr rowPtr = (IntPtr)((long)tcpTablePtr + Marshal.SizeOf(tcpTable.dwNumEntries)); for (int i = 0; i < tcpTable.dwNumEntries; i++) { rows[i] = Marshal.PtrToStructure<MIB_TCPROW_OWNER_PID>(rowPtr); rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(typeof(MIB_TCPROW_OWNER_PID))); // 筛选监听状态(MIB_TCP_STATE_LISTEN对应值为2) if (rows[i].dwState == 2) { // 转换端口字节序 ushort localPort = (ushort)((rows[i].dwLocalPort >> 8) | (rows[i].dwLocalPort << 8)); IPAddress localAddr = new IPAddress(rows[i].dwLocalAddr); try { Process process = Process.GetProcessById((int)rows[i].dwOwningPid); Console.WriteLine($"进程名: {process.ProcessName}, PID: {rows[i].dwOwningPid}, 监听地址: {localAddr}:{localPort}"); } catch (ArgumentException) { Console.WriteLine($"PID: {rows[i].dwOwningPid} 已退出,监听地址: {localAddr}:{localPort}"); } } } } finally { Marshal.FreeHGlobal(tcpTablePtr); } } } // 调用示例 class Program { static void Main() { TcpPortHelper.GetAllTcpListenerProcesses(); } }
说明:
- 代码默认针对IPv4,若需支持IPv6,需将
ulAf参数改为23,并替换为对应的IPv6结构体 - 同样需要管理员权限才能完整获取所有进程的端口关联信息
内容的提问来源于stack exchange,提问作者rams
相关产品推荐
相关产品推荐

