C#中已知本地地址、端口等信息如何获取对应进程ID?
实现方案
可以直接通过C#原生类库或Win32 API封装实现,无需调用netstat等外部程序或第三方工具。
.NET 5 / .NET Core 3.0 及以上版本实现
该版本框架的System.Net.NetworkInformation命名空间已原生支持获取网络连接对应的进程ID,无需额外封装:
using System.Net; using System.Net.NetworkInformation; // 示例查询参数,可根据你的实际需求替换 IPAddress localAddress = IPAddress.Parse("127.0.0.1"); int localPort = 12345; IPAddress remoteAddress = IPAddress.Parse("192.168.1.2"); int remotePort = 80; ProtocolType protocol = ProtocolType.Tcp; TcpState expectedState = TcpState.Established; int targetProcessId = 0; IPGlobalProperties ipProps = IPGlobalProperties.GetIPGlobalProperties(); if (protocol == ProtocolType.Tcp) { TcpConnectionInformation[] tcpConnections = ipProps.GetActiveTcpConnections(); foreach (var conn in tcpConnections) { // 匹配本地端点、远端端点、连接状态 if (conn.LocalEndPoint.Address.Equals(localAddress) && conn.LocalEndPoint.Port == localPort && conn.RemoteEndPoint.Address.Equals(remoteAddress) && conn.RemoteEndPoint.Port == remotePort && conn.State == expectedState) { targetProcessId = conn.ProcessId; break; } } } else if (protocol == ProtocolType.Udp) { // UDP为无连接协议,仅匹配本地监听端点即可 IPEndPoint[] udpListeners = ipProps.GetActiveUdpListeners(); foreach (var listener in udpListeners) { if (listener.Address.Equals(localAddress) && listener.Port == localPort) { // UDP的ProcessId属性从.NET Core 3.0开始支持 targetProcessId = listener.ProcessId; break; } } } if (targetProcessId > 0) { Console.WriteLine($"匹配到的进程ID为:{targetProcessId}"); }
.NET Framework 版本实现
.NET Framework 原生TcpConnectionInformation未提供ProcessId属性,需要通过P/Invoke调用Windows IP Helper API的GetExtendedTcpTable、GetExtendedUdpTable函数实现,核心实现代码如下:
using System; using System.Net; using System.Runtime.InteropServices; public static class IpHelper { [StructLayout(LayoutKind.Sequential)] private struct MIB_TCPROW_OWNER_PID { public uint state; public uint localAddr; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] localPort; public uint remoteAddr; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] remotePort; public uint owningPid; } [DllImport("iphlpapi.dll", SetLastError = true)] private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int dwSize, bool bOrder, int af, int tableClass, uint reserved = 0); private const int AF_INET = 2; private const int TCP_TABLE_OWNER_PID_CONNECTIONS = 5; public static int GetTcpConnectionProcessId(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint) { int bufferSize = 0; GetExtendedTcpTable(IntPtr.Zero, ref bufferSize, false, AF_INET, TCP_TABLE_OWNER_PID_CONNECTIONS); IntPtr buffer = Marshal.AllocHGlobal(bufferSize); try { uint ret = GetExtendedTcpTable(buffer, ref bufferSize, false, AF_INET, TCP_TABLE_OWNER_PID_CONNECTIONS); if (ret != 0) return 0; int rowCount = Marshal.ReadInt32(buffer); IntPtr rowPtr = buffer + Marshal.SizeOf(typeof(int)); for (int i = 0; i < rowCount; i++) { MIB_TCPROW_OWNER_PID row = Marshal.PtrToStructure<MIB_TCPROW_OWNER_PID>(rowPtr); IPAddress rowLocalAddr = new IPAddress(row.localAddr); int rowLocalPort = (row.localPort[0] << 8) + row.localPort[1]; IPAddress rowRemoteAddr = new IPAddress(row.remoteAddr); int rowRemotePort = (row.remotePort[0] << 8) + row.remotePort[1]; if (rowLocalAddr.Equals(localEndPoint.Address) && rowLocalPort == localEndPoint.Port && rowRemoteAddr.Equals(remoteEndPoint.Address) && rowRemotePort == remoteEndPoint.Port) { return (int)row.owningPid; } rowPtr += Marshal.SizeOf(typeof(MIB_TCPROW_OWNER_PID)); } return 0; } finally { Marshal.FreeHGlobal(buffer); } } }
注意事项
- 读取系统级进程的网络连接信息时,程序需要以管理员权限运行,否则部分进程ID可能返回0
- 如果需要匹配IPv6地址,只需将上述代码中的地址族参数从
AF_INET改为AF_INET6并对应调整结构体定义即可 - UDP协议无连接状态属性,查询时仅需匹配本地监听端点信息
内容的提问来源于stack exchange,提问作者Akash Kumar
相关产品推荐
相关产品推荐

