Mattl
Mattl

Reputation: 1618

How to check if a TCP port is available with Delphi?

Is there a more elegant way of checking if a TCP port is available with Delphi other than catching a netstat call?

Upvotes: 7

Views: 21920

Answers (6)

SteveS
SteveS

Reputation: 407

Based on Silver's example above, and since in many cases you want to find an available port rather than just verifying that a given port is in use:

uses
  //Indy V10
  IdContext,
  IdSocketHandle,
  IdTcpServer;

type
  //our port-checking tool
  TPortChk = class(TIdTCPServer)
    procedure OnExec(AContext: TIdContext);
  end;

procedure TPortChk.OnExec(AContext: TIdContext);
begin
  //does nothing, but must exist and be hooked
end;

//check a TCP port to see if it's already in use.
//normally used before opening a listener.
function PortAvailable(APort: Word): Boolean;
var
  svr: TPortChk;
  bnd: TIdSocketHandle;
begin
  //assume our port is available
  Result := True;
  //create our checking object
  svr := TPortChk.Create;
  try
    //set the execute event
    svr.OnExecute := svr.OnExec;
    //loop looking for an available port
    try
      //set up the binding for our local system and the
      //port in question
      bnd := svr.Bindings.Add;
      bnd.IP := '127.0.0.1';
      bnd.Port := APort;
      //try to bind.  This will throw an EIdCouldNotBindSocket
      //exception if the port is already in use.
      svr.Active := True;
      //if we get here, the port is *currently* available.
      //close the server and bail
      svr.Active := False;
      Exit;
    except
      //whoops, port's in use (or some related failure)
      Result := False;
    end;
  finally
    svr.Free;
  end;
end;

//search a range of ports for the first available
function FindAvailablePort(First, Count: Word): Word;
var
  svr: TPortChk;
  bnd: TIdSocketHandle;
begin
  //assume our initial port is available
  Result := First;
  //create our checking object
  svr := TPortChk.Create;
  try
    //set the execute event
    svr.OnExecute := svr.OnExec;
    //loop looking for an available port
    while (Result - First) < Count do begin
      try
        //set up the binding for our local system and the
        //port in question
        bnd := svr.Bindings.Add;
        bnd.IP := '127.0.0.1';
        bnd.Port := Result;
        //try to bind.  This will throw an EIdCouldNotBindSocket
        //exception if the port is already in use.
        svr.Active := True;
        //if we get here, we found our available port, so kill the
        //server and bail
        svr.Active := False;
        Exit;
      except
        Inc(Result);
        svr.Bindings.Clear;
      end;
    end;
    //if we get here, all of our possible ports are in use,
    //so return $FFFF to indicate that no port is available
    Result := $FFFF;
  finally
    svr.Free;
  end;
end;

Upvotes: 0

Silver Zachara
Silver Zachara

Reputation: 3228

Using an Indy.Sockets v10 TIdTCPServer component:

function TExample.IsTCPPortAvailable(const APort: Word): Boolean;
var
  LTCPServer: TIdTCPServer;
  LBinding: TIdSocketHandle;
begin
  Result := True;

  LTCPServer := TIdTCPServer.Create;
  try
    try
      with LTCPServer do
      begin
        DefaultPort   := APort;
        LBinding      := Bindings.Add;
        LBinding.IP   := '127.0.0.1';
        LBinding.Port := APort;
        OnExecute     := TCPServerExecute;
        Active        := True;
      end;
    finally
      LTCPServer.Free;
    end;
  except on EIdCouldNotBindSocket do
    Result := False;
  end;
end;

procedure TExample.TCPServerExecute(AContext: TIdContext);
begin
end;

Upvotes: 2

Jim McKeeth
Jim McKeeth

Reputation: 38703

netstat information can be retrieved by calling the GetTcpTable and GetUdpTable functions in the IP Helper API, or IPHLPAPI.DLL. For more information on calling the IPHLPAPI.DLL from Delphi, check out this Network traffic monitor. There are some wrappers for it too, and it is part of JEDI API Library.

I wrote a Delphi version of NetStat long ago, but have since lost the source code. Those resources should get you started though.

Upvotes: 6

skamradt
skamradt

Reputation: 15538

The following code from Synapse works very well:

uses
  blcksock;

function PortAvailable(Port:STring):boolean;
var
  svr : TTCPBlockSocket;
begin
  svr := TTCPBlockSocket.Create;
  try
    svr.Bind('0.0.0.0',Port);
    svr.Listen;
    result := svr.LastError = 0;
    Svr.CloseSocket;
  finally
    svr.Free;
  end;
end;

Upvotes: 4

RRUZ
RRUZ

Reputation: 136381

@Mattl, if Available means open for you, you can use this code.

program CheckTCP_PortOpen;

{$APPTYPE CONSOLE}

uses
  Winsock; //Windows Sockets API Unit

    function PortTCPIsOpen(dwPort : Word; ipAddressStr:string) : boolean;
    var
      client : sockaddr_in;//sockaddr_in is used by Windows Sockets to specify a local or remote endpoint address
      sock   : Integer;
    begin
        client.sin_family      := AF_INET;
        client.sin_port        := htons(dwPort);//htons converts a u_short from host to TCP/IP network byte order.
        client.sin_addr.s_addr := inet_addr(PChar(ipAddressStr)); //the inet_addr function converts a string containing an IPv4 dotted-decimal address into a proper address for the IN_ADDR structure.
        sock  :=socket(AF_INET, SOCK_STREAM, 0);//The socket function creates a socket 
        Result:=connect(sock,client,SizeOf(client))=0;//establishes a connection to a specified socket.
    end;

var
  ret    : Integer;
  wsdata : WSAData;
begin
  Writeln('Init WinSock');
  ret := WSAStartup($0002, wsdata);//initiates use of the Winsock
  if ret<>0 then exit;
  try
    Writeln('Description : '+wsData.szDescription);
    Writeln('Status      : '+wsData.szSystemStatus);

    if PortTCPIsOpen(80,'127.0.0.1') then
    Writeln('Open')
    else
    Writeln('Close');

  finally
  WSACleanup; //terminates use of the Winsock
  end;

  Readln;
end.

Upvotes: 7

zz1433
zz1433

Reputation: 3586

I guess you can use Indy's components to do that. For instance a TIdHTTPServer will raise an exception if a port is in use when it is being opened.

So basically you could create such component, bind it to localhost:<yourport> and if an exception is raised ( catch it and check it ) then the port is probably in use, else it is free.

I guess other indy components can tell if a port is open or not, but I can't look at it right now.

This was just to give you an approach.

Upvotes: 11

Related Questions