首页 > 代码库 > 根据端口查找占用进程——API方法

根据端口查找占用进程——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 valueTableClass valuepTcpTable structure
AF_INETTCP_TABLE_BASIC_ALLMIB_TCPTABLE
TCP_TABLE_BASIC_CONNECTIONSMIB_TCPTABLE
TCP_TABLE_BASIC_LISTENERMIB_TCPTABLE
TCP_TABLE_OWNER_MODULE_ALLMIB_TCPTABLE_OWNER_MODULE
TCP_TABLE_OWNER_MODULE_CONNECTIONSMIB_TCPTABLE_OWNER_MODULE
TCP_TABLE_OWNER_MODULE_LISTENERMIB_TCPTABLE_OWNER_MODULE
TCP_TABLE_OWNER_PID_ALLMIB_TCPTABLE_OWNER_PID
TCP_TABLE_OWNER_PID_CONNECTIONSMIB_TCPTABLE_OWNER_PID
TCP_TABLE_OWNER_PID_LISTENERMIB_TCPTABLE_OWNER_PID
AF_INET6TCP_TABLE_OWNER_MODULE_ALLMIB_TCP6TABLE_OWNER_MODULE
TCP_TABLE_OWNER_MODULE_CONNECTIONSMIB_TCP6TABLE_OWNER_MODULE
TCP_TABLE_OWNER_MODULE_LISTENERMIB_TCP6TABLE_OWNER_MODULE
TCP_TABLE_OWNER_PID_ALLMIB_TCP6TABLE_OWNER_PID
TCP_TABLE_OWNER_PID_CONNECTIONSMIB_TCP6TABLE_OWNER_PID
TCP_TABLE_OWNER_PID_LISTENERMIB_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 valueTableClass valuepUdpTable structure
AF_INETUDP_TABLE_BASICMIB_UDPTABLE
UDP_TABLE_OWNER_MODULEMIB_UDPTABLE_OWNER_MODULE
UDP_TABLE_OWNER_PIDMIB_UDPTABLE_OWNER_PID
AF_INET6UDP_TABLE_BASICMIB_UDP6TABLE
UDP_TABLE_OWNER_MODULEMIB_UDP6TABLE_OWNER_MODULE
UDP_TABLE_OWNER_PIDMIB_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 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 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

根据端口查找占用进程——API方法