获取Windows下某进程监听的TCP/UDP端口
1、在Windows下用CMD netstat命令可以获得当前进程监听端口号的信息,如netstat -ano可以看到IP、port、状态和监听的PID。
那么可以执行CMD这个进程得到监听的端口号信息,C#代码如下:
//进程id int pid = ProcInfo.ProcessID; //存放进程使用的端口号链表 List<int> ports = new List<int>(); Process pro = new Process(); pro.StartInfo.FileName = "cmd.exe"; pro.StartInfo.UseShellExecute = false; pro.StartInfo.RedirectStandardInput = true; pro.StartInfo.RedirectStandardOutput = true; pro.StartInfo.RedirectStandardError = true; pro.StartInfo.CreateNoWindow = true; pro.Start(); pro.StandardInput.WriteLine("netstat -ano"); pro.StandardInput.WriteLine("exit"); Regex reg = new Regex("\\s+", RegexOptions.Compiled); string line = null; ports.Clear(); while ((line = pro.StandardOutput.ReadLine()) != null) { line = line.Trim(); if (line.StartsWith("TCP", StringComparison.OrdinalIgnoreCase)) { line = reg.Replace(line, ","); string[] arr = line.Split(','); if (arr[4] == pid.ToString()) { string soc = arr[1]; int pos = soc.LastIndexOf(':'); int pot = int.Parse(soc.Substring(pos + 1)); ports.Add(pot); } } else if (line.StartsWith("UDP", StringComparison.OrdinalIgnoreCase)) { line = reg.Replace(line, ","); string[] arr = line.Split(','); if (arr[3] == pid.ToString()) { string soc = arr[1]; int pos = soc.LastIndexOf(':'); int pot = int.Parse(soc.Substring(pos + 1)); ports.Add(pot); } } } pro.Close();
2、如果不执行CMD进程,如何获得?可以参考这篇文章http://www.cnblogs.com/BoyXiao/archive/2012/02/20/2359273.html
文章介绍了使用Windows API获得进程和端口的映射关系:
(1)根据进程 ID 获得该进程所打开的所有的 TCP 和 UDP 端口。
(2)根据端口号来获得打开该端口的进程。
C语言代码如下:
// ProcessorPort.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #include <Windows.h> #include <Psapi.h> #include <Iprtrmib.h> #include <Winsock2.h> #pragma comment(lib,"Psapi.lib") #pragma comment(lib,"Iphlpapi.Lib") #pragma comment(lib,"WS2_32.lib") enum TcpOrUdp { TcpType, UdpType }; typedef struct { DWORD dwState; //连接状态 DWORD dwLocalAddr; //本地地址 DWORD dwLocalPort; //本地端口 DWORD dwRemoteAddr; //远程地址 DWORD dwRemotePort; //远程端口 DWORD dwProcessId; //进程标识 }MIB_TCPEXROW,*PMIB_TCPEXROW; typedef struct { DWORD dwLocalAddr; //本地地址 DWORD dwLocalPort; //本地端口 DWORD dwProcessId; //进程标识 }MIB_UDPEXROW,*PMIB_UDPEXROW; typedef struct { DWORD dwState; //连接状态 DWORD dwLocalAddr; //本地地址 DWORD dwLocalPort; //本地端口 DWORD dwRemoteAddr; //远程地址 DWORD dwRemotePort; //远程端口 DWORD dwProcessId; //进程标识 DWORD Unknown; //待定标识 }MIB_TCPEXROW_VISTA,*PMIB_TCPEXROW_VISTA; typedef struct { DWORD dwNumEntries; MIB_TCPEXROW table[ANY_SIZE]; }MIB_TCPEXTABLE,*PMIB_TCPEXTABLE; typedef struct { DWORD dwNumEntries; MIB_TCPEXROW_VISTA table[ANY_SIZE]; }MIB_TCPEXTABLE_VISTA,*PMIB_TCPEXTABLE_VISTA; typedef struct { DWORD dwNumEntries; MIB_UDPEXROW table[ANY_SIZE]; }MIB_UDPEXTABLE,*PMIB_UDPEXTABLE; //=====================================================================================// //Name: DWORD AllocateAndGetTcpExTableFromStack() // // //Descripion: 该函数仅仅只在 Windows XP,Windows Server 2003 下有效 // //=====================================================================================// typedef DWORD (WINAPI *PFNAllocateAndGetTcpExTableFromStack)( PMIB_TCPEXTABLE *pTcpTabel, bool bOrder, HANDLE heap, DWORD zero, DWORD flags ); //=====================================================================================// //Name: DWORD AllocateAndGetUdpExTableFromStack() // //Descripion: 该函数仅仅只在 XP,Windows Server 2003 下有效 // //=====================================================================================// typedef DWORD (WINAPI *PFNAllocateAndGetUdpExTableFromStack)( PMIB_UDPEXTABLE *pUdpTable, bool bOrder, HANDLE heap, DWORD zero, DWORD flags ); //=====================================================================================// //Name: DWORD InternalGetTcpTable2() // //Descripion: 该函数在 Windows Vista 以及 Windows 7 下面效 // //=====================================================================================// typedef DWORD (WINAPI *PFNInternalGetTcpTable2)( PMIB_TCPEXTABLE_VISTA *pTcpTable_Vista, HANDLE heap, DWORD flags ); //=====================================================================================// //Name: DWORD InternalGetUdpTableWithOwnerPid() // //Descripion: 该函数在 Windows Vista 以及 Windows 7 下面效 // //=====================================================================================// typedef DWORD (WINAPI *PFNInternalGetUdpTableWithOwnerPid)( PMIB_UDPEXTABLE *pUdpTable, HANDLE heap, DWORD flags ); //=====================================================================================// //Name: DWORD GetProcessIdByPort() // //Descripion: 根据端口号得到打开该端口号的进程ID(支持 XP,Server 2003,Vista,Win7) // //=====================================================================================// extern "C" __declspec(dllexport) DWORD __stdcall GetProcessIdByPort(TcpOrUdp type, DWORD dwPort) { HMODULE hModule = LoadLibraryW(L"iphlpapi.dll"); if (hModule == NULL) { return 0; } if(type == TcpType) { // 表明查询的是 TCP 信息 PFNAllocateAndGetTcpExTableFromStack pAllocateAndGetTcpExTableFromStack; pAllocateAndGetTcpExTableFromStack = (PFNAllocateAndGetTcpExTableFromStack)GetProcAddress(hModule, "AllocateAndGetTcpExTableFromStack"); if (pAllocateAndGetTcpExTableFromStack != NULL) { // 表明为 XP 或者 Server 2003 操作系统 PMIB_TCPEXTABLE pTcpExTable = NULL; if (pAllocateAndGetTcpExTableFromStack(&pTcpExTable, TRUE, GetProcessHeap(), 0, AF_INET) != 0) { if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } for (UINT i = 0; i < pTcpExTable->dwNumEntries; i++) { // 过滤掉数据,只查询我们需要的进程数据 if(dwPort == ntohs(0x0000FFFF & pTcpExTable->table[i].dwLocalPort)) { DWORD dwProcessId = pTcpExTable->table[i].dwProcessId; if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return dwProcessId; } } if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } else { // 表明为 Vista 或者 7 操作系统 PMIB_TCPEXTABLE_VISTA pTcpExTable = NULL; PFNInternalGetTcpTable2 pInternalGetTcpTable2 = (PFNInternalGetTcpTable2)GetProcAddress(hModule, "InternalGetTcpTable2"); if (pInternalGetTcpTable2 == NULL) { if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } if (pInternalGetTcpTable2(&pTcpExTable, GetProcessHeap(), 1)) { if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } for (UINT i = 0;i < pTcpExTable->dwNumEntries; i++) { // 过滤掉数据,只查询我们需要的进程数据 if(dwPort == ntohs(0x0000FFFF & pTcpExTable->table[i].dwLocalPort)) { DWORD dwProcessId = pTcpExTable->table[i].dwProcessId; if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return dwProcessId; } } if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } } else if(type == UdpType) { // 表明查询的是 UDP 信息 PMIB_UDPEXTABLE pUdpExTable = NULL; PFNAllocateAndGetUdpExTableFromStack pAllocateAndGetUdpExTableFromStack; pAllocateAndGetUdpExTableFromStack = (PFNAllocateAndGetUdpExTableFromStack)GetProcAddress(hModule,"AllocateAndGetUdpExTableFromStack"); if (pAllocateAndGetUdpExTableFromStack != NULL) { // 表明为 XP 或者 Server 2003 操作系统 if (pAllocateAndGetUdpExTableFromStack(&pUdpExTable, TRUE, GetProcessHeap(), 0, AF_INET) != 0) { if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } for (UINT i = 0; i < pUdpExTable->dwNumEntries; i++) { // 过滤掉数据,只查询我们需要的进程数据 if (dwPort == ntohs(0x0000FFFF & pUdpExTable->table[i].dwLocalPort)) { DWORD dwProcessId = pUdpExTable->table[i].dwProcessId; if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return dwProcessId; } } if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } else { // 表明为 Vista 或者 7 操作系统 PFNInternalGetUdpTableWithOwnerPid pInternalGetUdpTableWithOwnerPid; pInternalGetUdpTableWithOwnerPid = (PFNInternalGetUdpTableWithOwnerPid)GetProcAddress(hModule, "InternalGetUdpTableWithOwnerPid"); if (pInternalGetUdpTableWithOwnerPid != NULL) { if (pInternalGetUdpTableWithOwnerPid(&pUdpExTable, GetProcessHeap(), 1)) { if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } for (UINT i = 0; i < pUdpExTable->dwNumEntries; i++) { // 过滤掉数据,只查询我们需要的进程数据 if (dwPort == ntohs(0x0000FFFF & pUdpExTable->table[i].dwLocalPort)) { DWORD dwProcessId = pUdpExTable->table[i].dwProcessId; if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return dwProcessId; } } } if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return 0; } } else { FreeLibrary(hModule); hModule = NULL; return -1; } } //===========================================================================================// //Name: DWORD GetAllPortByProcessId() // //Descripion: 根据进程ID得到该进程所打开的所有的端口号,并且在 dwAllPort 数组中返回所有端口号// // 其中 dwMaxLen 为数组的长度,函数的返回值为进程所打开的端口的数目 // // (支持 XP,Server 2003,Vista,Win7) // //===========================================================================================// extern "C" __declspec(dllexport) DWORD __stdcall GetAllPortByProcessId(TcpOrUdp type, DWORD dwProcessId, DWORD * dwAllPort, DWORD dwMaxLen) { DWORD dwPortCount = 0; HMODULE hModule = LoadLibraryW(L"iphlpapi.dll"); if (hModule == NULL) { return dwPortCount; } if(type == TcpType) { // 表明查询的是 UDP 信息 PFNAllocateAndGetTcpExTableFromStack pAllocateAndGetTcpExTableFromStack; pAllocateAndGetTcpExTableFromStack = (PFNAllocateAndGetTcpExTableFromStack)GetProcAddress(hModule, "AllocateAndGetTcpExTableFromStack"); if (pAllocateAndGetTcpExTableFromStack != NULL) { // 表明为 XP 或者 Server 2003 操作系统 PMIB_TCPEXTABLE pTcpExTable = NULL; if (pAllocateAndGetTcpExTableFromStack(&pTcpExTable, TRUE, GetProcessHeap(), 0, AF_INET) != 0) { if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } for (UINT i = 0; i < pTcpExTable->dwNumEntries; i++) { // 过滤掉数据,只获取我们要查询的进程的 Port 信息 if(dwProcessId == pTcpExTable->table[i].dwProcessId) { if(dwPortCount < dwMaxLen) { dwAllPort[dwPortCount] = ntohs(0x0000FFFF & pTcpExTable->table[i].dwLocalPort); dwPortCount++; } } } if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } else { // 表明为 Vista 或者 7 操作系统 PMIB_TCPEXTABLE_VISTA pTcpExTable = NULL; PFNInternalGetTcpTable2 pInternalGetTcpTable2 = (PFNInternalGetTcpTable2)GetProcAddress(hModule, "InternalGetTcpTable2"); if (pInternalGetTcpTable2 == NULL) { if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } if (pInternalGetTcpTable2(&pTcpExTable, GetProcessHeap(), 1)) { if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } for (UINT i = 0;i < pTcpExTable->dwNumEntries; i++) { // 过滤掉数据,只获取我们要查询的进程的 TCP Port 信息 if(dwProcessId == pTcpExTable->table[i].dwProcessId) { if(dwPortCount < dwMaxLen) { dwAllPort[dwPortCount] = ntohs(0x0000FFFF & pTcpExTable->table[i].dwLocalPort); dwPortCount++; } } } if (pTcpExTable) { HeapFree(GetProcessHeap(), 0, pTcpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } } else if(type == UdpType) { // 表明查询的是 UDP 信息 PMIB_UDPEXTABLE pUdpExTable = NULL; PFNAllocateAndGetUdpExTableFromStack pAllocateAndGetUdpExTableFromStack; pAllocateAndGetUdpExTableFromStack = (PFNAllocateAndGetUdpExTableFromStack)GetProcAddress(hModule,"AllocateAndGetUdpExTableFromStack"); if (pAllocateAndGetUdpExTableFromStack != NULL) { // 表明为 XP 或者 Server 2003 操作系统 if (pAllocateAndGetUdpExTableFromStack(&pUdpExTable, TRUE, GetProcessHeap(), 0, AF_INET) != 0) { if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } for (UINT i = 0; i < pUdpExTable->dwNumEntries; i++) { // 过滤掉数据,只获取我们要查询的进程的 UDP Port信息 if(dwProcessId == pUdpExTable->table[i].dwProcessId) { if(dwPortCount < dwMaxLen) { dwAllPort[dwPortCount] = ntohs(0x0000FFFF & pUdpExTable->table[i].dwLocalPort); dwPortCount++; } } } if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } else { // 表明为 Vista 或者 7 操作系统 PFNInternalGetUdpTableWithOwnerPid pInternalGetUdpTableWithOwnerPid; pInternalGetUdpTableWithOwnerPid = (PFNInternalGetUdpTableWithOwnerPid)GetProcAddress(hModule, "InternalGetUdpTableWithOwnerPid"); if (pInternalGetUdpTableWithOwnerPid != NULL) { if (pInternalGetUdpTableWithOwnerPid(&pUdpExTable, GetProcessHeap(), 1)) { if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } for (UINT i = 0; i < pUdpExTable->dwNumEntries; i++) { // 过滤掉数据,只获取我们要查询的进程的 UDP Port信息 if(dwProcessId == pUdpExTable->table[i].dwProcessId) { if(dwPortCount < dwMaxLen) { dwAllPort[dwPortCount] = ntohs(0x0000FFFF & pUdpExTable->table[i].dwLocalPort); dwPortCount++; } } } } if (pUdpExTable) { HeapFree(GetProcessHeap(), 0, pUdpExTable); } FreeLibrary(hModule); hModule = NULL; return dwPortCount; } } else { FreeLibrary(hModule); hModule = NULL; return dwPortCount; } }
如果要在.Net平台下使用,将其编译成DLL,使用PInvoke得到DLL导出函数就可以了。
C#测试代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace ProcessorPortDllTest { public enum TcpOrUdp { TcpType, UdpType }; public class ProcessPortHelper { [DllImport("ProcessorPort.dll",CallingConvention = CallingConvention.StdCall)] public extern static uint GetProcessIdByPort(TcpOrUdp type, uint dwPort); [DllImport("ProcessorPort.dll",CallingConvention = CallingConvention.StdCall)] public extern static uint GetAllPortByProcessId(TcpOrUdp type, uint dwProcessId, uint[] dwAllPort, uint dwMaxLen); } class Program { static void Main(string[] args) { uint port = 1025; uint processorId = ProcessPortHelper.GetProcessIdByPort(TcpOrUdp.TcpType, port); Console.WriteLine("Port {0} is using by processor {1}",port,processorId); uint processorId1 = 1072; uint[] TcpPorts = new uint[100]; uint count = ProcessPortHelper.GetAllPortByProcessId(TcpOrUdp.TcpType, processorId1, TcpPorts, (uint)TcpPorts.Length); Console.WriteLine("Processor {0} is using TCP port: ", processorId1); for (uint i = 0; i < count; ++i) { Console.WriteLine(TcpPorts[i]); } uint[] UdpPorts = new uint[100]; uint count1 = ProcessPortHelper.GetAllPortByProcessId(TcpOrUdp.UdpType, processorId1, UdpPorts, (uint)UdpPorts.Length); Console.WriteLine("Processor {0} is using UDP port: ", processorId1); for (uint i = 0; i < count1; ++i) { Console.WriteLine(UdpPorts[i]); }
Console.ReadKey(); } } }
获得进程监听TCP/UDP端口号的DLL:ProcessorPort.rar