如何找出哪个端口使用进程?

时间:2013-06-05 12:12:15

标签: delphi networking delphi-xe3 ports

我想知道如何找出程序/进程使用的端口。我想知道一个进程中使用过的端口,然后在标签中写入。

是否有可用的单位或功能?

2 个答案:

答案 0 :(得分:11)

您可以使用传递GetExtendedTcpTable TableClass值的TCP_TABLE_OWNER_PID_ALL函数,这将返回MIB_TCPTABLE_OWNER_PID结构,该结构是MIB_TCPROW_OWNER_PID记录的数组,此结构包含端口号(dwLocalPort)和进程的PID(dwOwningPid),您可以使用CreateToolhelp32Snapshot函数解析PID的名称。

样品

{$APPTYPE CONSOLE}

uses
  WinSock,
  TlHelp32,
  Classes,
  Windows,
  SysUtils;

const
   ANY_SIZE = 1;
   iphlpapi = 'iphlpapi.dll';
   TCP_TABLE_OWNER_PID_ALL = 5;

type
  TCP_TABLE_CLASS = Integer;

  PMibTcpRowOwnerPid = ^TMibTcpRowOwnerPid;
  TMibTcpRowOwnerPid  = packed record
    dwState     : DWORD;
    dwLocalAddr : DWORD;
    dwLocalPort : DWORD;
    dwRemoteAddr: DWORD;
    dwRemotePort: DWORD;
    dwOwningPid : DWORD;
    end;

  PMIB_TCPTABLE_OWNER_PID  = ^MIB_TCPTABLE_OWNER_PID;
  MIB_TCPTABLE_OWNER_PID = packed record
   dwNumEntries: DWORD;
   table: Array [0..ANY_SIZE - 1] of TMibTcpRowOwnerPid;
  end;

var
   GetExtendedTcpTable:function  (pTcpTable: Pointer; dwSize: PDWORD; bOrder: BOOL; lAf: ULONG; TableClass: TCP_TABLE_CLASS; Reserved: ULONG): DWord; stdcall;


function GetPIDName(hSnapShot: THandle; PID: DWORD): string;
var
  ProcInfo: TProcessEntry32;
begin
  ProcInfo.dwSize := SizeOf(ProcInfo);
  if not Process32First(hSnapShot, ProcInfo) then
     Result := 'Unknow'
  else
  repeat
    if ProcInfo.th32ProcessID = PID then
       Result := ProcInfo.szExeFile;
  until not Process32Next(hSnapShot, ProcInfo);
end;

procedure ShowTCPPortsUsed(const AppName : string);
var
   Error      : DWORD;
   TableSize  : DWORD;
   i          : integer;
   pTcpTable  : PMIB_TCPTABLE_OWNER_PID;
   SnapShot   : THandle;
   LAppName   : string;
   LPorts     : TStrings;
begin
  LPorts:=TStringList.Create;
  try
    TableSize := 0;
    //Get the size o the tcp table
    Error := GetExtendedTcpTable(nil, @TableSize, False, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
    if Error <> ERROR_INSUFFICIENT_BUFFER then exit;

    GetMem(pTcpTable, TableSize);
    try
     SnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
     try
       //get the tcp table data
       if GetExtendedTcpTable(pTcpTable, @TableSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) = NO_ERROR then
          for i := 0 to pTcpTable.dwNumEntries - 1 do
          begin
             LAppName:=GetPIDName(SnapShot, pTcpTable.Table[i].dwOwningPid);
             if SameText(LAppName, AppName) and (LPorts.IndexOf(IntToStr(pTcpTable.Table[i].dwLocalPort))=-1) then
               LPorts.Add(IntToStr(pTcpTable.Table[i].dwLocalPort));
          end;
     finally
       CloseHandle(SnapShot);
     end;
    finally
       FreeMem(pTcpTable);
    end;

    Writeln(LPorts.Text);

  finally
    LPorts.Free;
  end;

end;

var
   hModule : THandle;
begin
  try
    hModule := LoadLibrary(iphlpapi);
    try
      GetExtendedTcpTable := GetProcAddress(hModule, 'GetExtendedTcpTable');
      ShowTCPPortsUsed('Skype.exe');
    finally
      FreeLibrary(hModule);
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

答案 1 :(得分:0)

为了获得正确的端口号,您必须使用 ntohs()

if SameText(LAppName, AppName) and
  (LPorts.IndexOf(IntToStr(pTcpTable.Table[i].dwLocalPort))=-1) then
  LPorts.Add(IntToStr(ntohs(pTcpTable.Table[i].dwLocalPort)));

更多信息here