根據端口查找佔用進程——API方法

       轉自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

       轉自http://blog.csdn.net/tht2009/article/details/40458425

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章