C#获取端口被哪个进程占用

之前网上看了不少方法,多数都是靠cmd进程来抓取数据的。也就是相当于调用系统命令提示符,输入netstat -ano之类的命令,然后由程序获取到cmd返回的数据进行输出,非常方便。但是却过于简陋,找了很多地方,也在MSDN上提问过,回答都是因为系统没有此API无法获取。
在网上也有别人发的netstat源码,测试过都无效。也可能是因为系统是win7的缘故。

后来在网上看到一篇文章就是写这个的,作者是用C++写的,并且代码对XP以及XP以上的系统在方法上有区分,虽然作者在代码中没有写是否支持win8,但是经过测试win8下是正常的。

文章链接:http://www.cnblogs.com/BoyXiao/archive/2012/02/20/2359273.html

如果用C#的话,自然是没有这种底层的能力了。所以只好通过DllImport的方式调用C++中的方法了。

将作者源代码编译为dll,在C#中就可以引用了。

[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);

这样就可以在C#中调用其中的方法:

比如获取端口被哪个进程占用,dll中的方法返回的是pid,需要手动将pid转换为进程名。

public static String GetProcessPort(uint p)
{
	uint port = p;
	String process = "";
	uint processorId = ProcessPortHelper.GetProcessIdByPort(TcpOrUdp.TcpType, port);
	if (processorId != 0)
	{
		process = "端口:" + port + " 被进程" + GetProcessNameByPort(processorId) + "占用\n";
		return process;
	}
	else
	{
		return "";
	}
}

还可以通过进程PID获取进程占用哪些端口:

public static String GetPortProcess(uint process)
{
	uint processorId1 = process;
	uint[] TcpPorts = new uint[100];
	uint count = ProcessPortHelper.GetAllPortByProcessId(TcpOrUdp.TcpType, processorId1, TcpPorts, (uint)TcpPorts.Length);
	String processPort = "进程:" + GetProcessNameByPort(processorId1) + "正在使用TCP端口:";
	for (uint i = 0; i < count; ++i)
	{
		processPort += TcpPorts[i].ToString() + "\n";
	}
	uint[] UdpPorts = new uint[100];
	uint count1 = ProcessPortHelper.GetAllPortByProcessId(TcpOrUdp.UdpType, processorId1, UdpPorts, (uint)UdpPorts.Length);
	processPort += "\n进程:" + GetProcessNameByPort(processorId1) + "正在使用UDP端口:";
	for (uint i = 0; i < count1; ++i)
	{
		processPort += UdpPorts[i].ToString() + "\n";
	}
	return processPort;
}

至于要获取pid所对应的进程名,可以使用C#中的方法,使用非常简单:

private static String GetProcessNameByPort(uint pid)
{
	try
	{
		int p = Convert.ToInt32(pid);
		Process localById = Process.GetProcessById(p);
		return localById.ProcessName;
	}
	catch
	{
		return pid.ToString();
	}
}

C++的源码:(转自原作者)

//Netstat -anb#include
#include "Psapi.h"
#include #pragma comment(lib,"Psapi.lib")
#pragma comment(lib,"Iphlpapi.Lib")
#pragma comment(lib,"WS2_32.lib")
#include
#include using namespace std;
using std::vector;
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) //
// //
//=====================================================================================//
DWORD 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) //
// //
//=====================================================================================//
DWORD 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;
}
}
int main()
{
DWORD dwAllPort[50];
DWORD dwMaxLen = 50; DWORD dwPort;
DWORD dwProcessId; DWORD dwResult = 0; DWORD dwInput = 0;
while(dwInput != 5)
{
cout<<"Input 1: Query TCP Port By Process ID;"<<endl;
cout<<"Input 2: Query UDP Port By Process ID;"<<endl;
cout<<"Input 3: Query Process ID By TCP Port;"<<endl;
cout<<"Input 4: Query Process ID By UDP Port;"<<endl;
cout<<"Input 5: Exit Application;"<<endl<<endl;
cout<<"Please Input Your Select Option: "; cin>>dwInput;
system("cls"); memset(dwAllPort, 0, sizeof(DWORD) * dwMaxLen); switch(dwInput)
{
case 1:
{
cout<<"Please Input The Process ID: "; cin>>dwProcessId;
dwResult = GetAllPortByProcessId(TcpType, dwProcessId, dwAllPort, dwMaxLen);
cout<<endl<<"=========Query TCP Port By Process ID Result : ========="<<endl;
for(int i=0;i<dwResult;i++)
{
cout<<"第 "< }
cout<<"========================================================"<<endl<<endl<<endl;
break;
}
case 2:
{
cout<<"Please Input The Process ID: "; cin>>dwProcessId;
dwResult = GetAllPortByProcessId(UdpType, dwProcessId, dwAllPort, dwMaxLen);
cout<<endl<<"=========Query UDP Port By Process ID Result : ========="<<endl;
for(int i=0;i<dwResult;i++)
{
cout<<"第 "< }
cout<<"========================================================"<<endl<<endl<<endl;
break;
}
case 3:
{
cout<<"Please Input The Port: "; cin>>dwPort;
dwResult = GetProcessIdByPort(TcpType, dwPort);
cout<<endl<<"=========Query Process ID By TCP Port Result : ========="<<endl;
cout<<"结果为: "<<dwResult<<endl;
cout<<"========================================================"<<endl<<endl<<endl;
break;
}
case 4:
{
cout<<"Please Input The Port: "; cin>>dwPort;
dwResult = GetProcessIdByPort(UdpType, dwPort);
cout<<endl<<"=========Query Process ID By UDP Port Result : ========="<<endl;
cout<<"结果为: "<<dwResult<<endl;
cout<<"========================================================"<<endl<<endl<<endl;
break;
}
case 5:
{
return 0;
}
default:
{
break;
}
}
} return 0;
}

 

程序中也可以使用循环传值的方式来获取所有端口的打开情况。

通过以上方法就可以实现C#下不使用CMD的方式来获取到进程和端口之间的关系。
程序运行起来就是这样:

QQ截图20140527233907
扫描速度还是非常理想的。至于程序中的UDP和TCP扫描,网上资料也不少,就不贴出来了。

本文中所提到的dll:链接: http://pan.baidu.com/s/1bnnISSB 密码: 9o2w

 


  1. 楼主,我最近也在研究这个东西,不知道能不能分享一下您的代码给我学习一下?

  2. 楼主提供的dll用不了(添加时报错:请确保此文件可访问并且是一个有效的程序集或COM组件)
    用vs2010编译源代码的生成的.dll 框架只能是在.net framework 4.0 以上的,我的程序是v3.5。。而生成v3.5的目标框架需要vs2008。所以最终还是没用上。。。
    还是感谢楼主的资源