轉自http://blog.csdn.net/tht2009/article/details/40458425
在開發聯網應用時,常常需要申請、綁定端口,這時就需判斷哪些端口可用或指定端口是否被佔用。在命令行窗口下,輸入“netstat -ano"命令可以顯示查看當前端口占用情況。如何在程序代碼中實現這個功能呢?
當然也可以執行cmd命令,通過分析返回文本來判斷。其實,Windows已經提供了獲取當前網絡連接狀態的API,這些API都位於動態庫Iphlpapi.dll中。跟查看端口情況相關的API主要有GetTcpTable、GetUdpTable、GetExtendedTcpTable、GetExtendedUdpTable,這四個API可以獲取當前系統TCP、UDP端口連接表,後兩個分別是前兩個的擴展版,可以獲得當前端口的佔用進程ID。
1、GetExtendedTcpTable
函數原型如下:
DWORD GetExtendedTcpTable(
_Out_ PVOID pTcpTable,
_Inout_ PDWORD pdwSize,
_In_ BOOL bOrder,
_In_ ULONG ulAf,
_In_ TCP_TABLE_CLASS TableClass,
_In_ ULONG Reserved
);
參數:
pTcpTable(指針類型): 存儲TCP端口連接信息表,具體結構類型根據ulAF和TableClass參數而定。
pdwSize(傳址):pTcpTable指向的內存大小,如果pdwSize比需要的空間小,函數返回一個ERROR_INSUFFICIENT_BUFFER錯誤,並將pdwSize 置爲所需大小。
bOrder(布爾): 返回結果是否排序。
ulAF(整數):IP類型。AF_INET——IPv4; AF_INET6——IPv6。
TableClass(枚舉): TCP_TABLE_CLASS 。根據ulAF,傳入相應不同值,返回的pTcpTable中結構類型不同。
typedef enum {
TCP_TABLE_BASIC_LISTENER,
TCP_TABLE_BASIC_CONNECTIONS,
TCP_TABLE_BASIC_ALL,
TCP_TABLE_OWNER_PID_LISTENER,
TCP_TABLE_OWNER_PID_CONNECTIONS,
TCP_TABLE_OWNER_PID_ALL,
TCP_TABLE_OWNER_MODULE_LISTENER,
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
TCP_TABLE_OWNER_MODULE_ALL
} TCP_TABLE_CLASS, *PTCP_TABLE_CLASS;
Reserved(保留):設爲0。
轉自http://blog.csdn.net/tht2009/article/details/40458425
pTcpTable指向結構類型與ulAF和TableClass取值關係如下:
ulAF value | TableClass value | pTcpTable structure |
AF_INET | TCP_TABLE_BASIC_ALL | MIB_TCPTABLE |
TCP_TABLE_BASIC_CONNECTIONS | MIB_TCPTABLE | |
TCP_TABLE_BASIC_LISTENER | MIB_TCPTABLE | |
TCP_TABLE_OWNER_MODULE_ALL | MIB_TCPTABLE_OWNER_MODULE | |
TCP_TABLE_OWNER_MODULE_CONNECTIONS | MIB_TCPTABLE_OWNER_MODULE | |
TCP_TABLE_OWNER_MODULE_LISTENER | MIB_TCPTABLE_OWNER_MODULE | |
TCP_TABLE_OWNER_PID_ALL | MIB_TCPTABLE_OWNER_PID | |
TCP_TABLE_OWNER_PID_CONNECTIONS | MIB_TCPTABLE_OWNER_PID | |
TCP_TABLE_OWNER_PID_LISTENER | MIB_TCPTABLE_OWNER_PID | |
AF_INET6 | TCP_TABLE_OWNER_MODULE_ALL | MIB_TCP6TABLE_OWNER_MODULE |
TCP_TABLE_OWNER_MODULE_CONNECTIONS | MIB_TCP6TABLE_OWNER_MODULE | |
TCP_TABLE_OWNER_MODULE_LISTENER | MIB_TCP6TABLE_OWNER_MODULE | |
TCP_TABLE_OWNER_PID_ALL | MIB_TCP6TABLE_OWNER_PID | |
TCP_TABLE_OWNER_PID_CONNECTIONS | MIB_TCP6TABLE_OWNER_PID | |
TCP_TABLE_OWNER_PID_LISTENER | MIB_TCP6TABLE_OWNER_PID |
2、GetExtendedUdpTable
函數原型如下:
DWORD GetExtendedUdpTable(
_Out_ PVOID pUdpTable,
_Inout_ PDWORD pdwSize,
_In_ BOOL bOrder,
_In_ ULONG ulAf,
_In_ UDP_TABLE_CLASS TableClass,
_In_ ULONG Reserved
);
參數:
pUdpTable(指針類型): 存儲UDP端口連接信息表,具體結構類型根據ulAF和TableClass參數而定。
pdwSize、bOrder、ulAF、Reserved:同TCP部分描述。
TableClass(枚舉): UDP_TABLE_CLASS 。根據ulAF,傳入相應不同值,返回的pUdpTable中結構類型不同。
typedef enum {
UDP_TABLE_BASIC,
UDP_TABLE_OWNER_PID,
UDP_TABLE_OWNER_MODULE
} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS;
pUdpTable指向結構類型與ulAF和TableClass取值關係如下:
ulAF value | TableClass value | pUdpTable structure |
AF_INET | UDP_TABLE_BASIC | MIB_UDPTABLE |
UDP_TABLE_OWNER_MODULE | MIB_UDPTABLE_OWNER_MODULE | |
UDP_TABLE_OWNER_PID | MIB_UDPTABLE_OWNER_PID | |
AF_INET6 | UDP_TABLE_BASIC | MIB_UDP6TABLE |
UDP_TABLE_OWNER_MODULE | MIB_UDP6TABLE_OWNER_MODULE | |
UDP_TABLE_OWNER_PID | MIB_UDP6TABLE_OWNER_PID |
根據上面介紹,可以很容易寫出查看佔用端口的進程功能:FindPidByTcpPort和FindPidByUdpPort函數。主要Delphi實現代碼如下:
/// <summary>通過指定TCP端口查找佔用進程PID</summary>
/// <param name="port :Integer">TCP端口號</param>
/// <returns>Integer: -1,執行出錯;0,指定端口未被佔用;>0,佔用進程PID</returns>
function FindPidByTcpPort(port: Cardinal): Integer;
/// <summary>通過指定UDP端口查找佔用進程PID</summary>
/// <param name="port :Integer">UDP端口號</param>
/// <returns>Integer: -1,執行出錯;0,指定端口未被佔用;>0,佔用進程PID</returns>
function FindPidByUdpPort(port: Cardinal): Integer;
轉自http://blog.csdn.net/tht2009/article/details/40458425
function FindPidByTcpPort(port: Cardinal): Integer;
var
pTcpTable: PMibTcpTableOwnerPID;
dwSize: DWORD;
i: Integer;
begin
Result := -1;
dwSize := 0;
//查詢大小
if GetExtendedTcpTable(nil, dwSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)
= ERROR_INSUFFICIENT_BUFFER then
begin
pTcpTable := AllocMem(dwSize);
//獲取TCP連接表
if GetExtendedTcpTable(pTcpTable, dwSize, True, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)
=NO_ERROR then
begin
port := htons(port);
for I := 0 to pTcpTable.dwNumEntries-1 do
begin
if pTcpTable.table[i].dwLocalPort = Port then
begin
Result := pTcpTable.table[i].dwOwningPid;
Break;
end;
end;
if Result<0 then
Result := 0;
end;
FreeMem(pTcpTable);
end;
end;
function FindPidByUdpPort(port: Cardinal): Integer;
var
pUdpTable: PMibUdpTableOwnerPID;
dwSize: DWORD;
i: Integer;
begin
Result := -1;
dwSize := 0;
//查詢大小
if GetExtendedUdpTable(nil, dwSize, FALSE, AF_INET, UDP_TABLE_OWNER_PID, 0)
= ERROR_INSUFFICIENT_BUFFER then
begin
pUdpTable := AllocMem(dwSize);
//獲取UDP連接表
if GetExtendedUdpTable(pUdpTable, dwSize, True, AF_INET, UDP_TABLE_OWNER_PID, 0)
=NO_ERROR then
begin
port := htons(port);
for I := 0 to pUdpTable.dwNumEntries-1 do
begin
if pUdpTable.table[i].dwLocalPort = Port then
begin
Result := pUdpTable.table[i].dwOwningPid;
Break;
end;
end;
if Result<0 then
Result := 0;
end;
FreeMem(pUdpTable);
end;
end;
其中聲明這兩個函數,定義MibUdpTableOwnerPID與MibTcpTableOwnerPID結構體部分請參照MSDN中介紹,也可下載完整代碼IpHlpApi2.pas查閱:http://www.colafile.com/file/2413129。