TCP/IP: is port X available ?

how do I know if a certain tcp/ip port is available ?

this doesn't work:

with wsocket1 do
 begin
  port:= '20000';
  proto:= 'tcp';
  try
    listen;
  except
    showmessage('port not available');
  end;
 end;

this only works when another app is LISTENNING in that port..
I tried the following:

I run a chat program that conects to another one in LOCALHOST,
both in my computer, ok I go to netstat and I see there are these
connections:

localhost:20000 --> localhost:30000
localhost:30000 --> localhost:20000

ok, once they are connected and not listenning.. just connected, I try the code above and I get these results:
if I try with port 20000 I get an error about winsock binding or something,
if I try with 30000 .. I get no error !!! like if the port was free while it's not...

thanks

 
LVL 3
bryan7Asked:
Who is Participating?
 
God_AresCommented:
>god_ares solution:
it worked.. giving different error numbers depending if port was listenning or already connected.. but I can't use that because it could leave in an inoperable state the app that is listenning..

a server socket can handle more than 1 connection...

let's suppose a program is listenning for the client on port 20000, once the client connects and disconnects the app will not listen again, ok using the proposed solution would could
leave the app not listenning.. I need something that doesn't interfere in any app that's listenning..



My solution can't interfere or leave the app in a inoperate state.. if you want to check if a port is being used just check on 127.0.0.1 if port x is listening by connectiong to it whit a client socket, that's all and it won't do any harm.

PROOF ME THAT I'M WRONG! and i'll find another way..
0
 
tomer_engelCommented:
a) every applciation determins it's own ports,,meaning , if you're writng serverand the client applciations you should write down in the Sockets propery the port.
b) if your'e writing only the server then run in a for loop until you find a port that isn't unsed(something like that):

for i:=1000 to 5000 do
begin
  try
    port := i;
    //connect
    break;//break out of the loop
  except
  end;//the try-except
end;//the for loop

otherwise i'm not fammiliar with a function/method/API function that do the check for ya.


:)
0
 
bryan7Author Commented:
that method doesn't work.. as I said above
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
nricoCommented:
So maybe the Try...Except doesn't work, but I'm sure you'll get an error from the TServerSocket if you're trying to listen on a port that's already occupied.
So instead of using the Try...Except, try hooking the OnError event of the TServerSocket and the OnException event of the TApplication variable, and see what those come up with if you try to listen on a port that you KNOW is occupied.

(I'm guessing for the OnException, personally)
0
 
jturpinCommented:
You could include a TClientSocket on the server side, then simply change the port to the one you want to connect to.

If it connects you know it is free.
0
 
RadlerCommented:
There are two worlds, Unix and M$.
To Unix machines following the RFC number ??? to detect the port/protocol/service name you should read the lmhost file, but is it true for M$ Windows ?

T++, Radler.
0
 
bryan7Author Commented:
Adjusted points from 50 to 100
0
 
bryan7Author Commented:
"So maybe the Try...Except doesn't work, but I'm sure you'll get an error from the                   TServerSocket if you're trying to listen on a port that's already occupied. "

nothing..
0
 
God_AresCommented:
don't use a server socket  use a client socket.. if it connects the port is being used.. simple...
soure:...

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ScktComp, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Edit3: TEdit;
    Label3: TLabel;
    Button1: TButton;
    Memo1: TMemo;
    Label4: TLabel;
    ding: TClientSocket;
    poin: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure dingConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure dingError(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure poinTimer(Sender: TObject);
    procedure dingRead(Sender: TObject; Socket: TCustomWinSocket);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ding.Active:=false;
  ding.Host:=edit3.Text;
  ding.Port:=strtoint(edit1.text);

  ding.Active:=true;

end;

procedure TForm1.dingConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  memo1.lines.add(inttostr(ding.port)+'  is listening');
  poin.Enabled:=true;
end;

procedure TForm1.dingError(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
  errorcode:=0;
  if ErrorEvent=eeGeneral then memo1.lines.add(inttostr(ding.port)+'  '+'The socket received an error message that does not fit into any of the following categories.');
  if ErrorEvent=eeSend then memo1.lines.add(inttostr(ding.port)+'  '+'An error occurred when trying to write to the socket connection.');
  if ErrorEvent=eeReceive then memo1.lines.add(inttostr(ding.port)+'  '+'An error occurred when trying to read from the socket connection.');
  if ErrorEvent=eeConnect then memo1.lines.add(inttostr(ding.port)+'  '+'A connection request that was already accepted could not be completed.');
  if ErrorEvent=eeDisconnect then memo1.lines.add(inttostr(ding.port)+'  '+'An error occurred when trying to close a connection.');
  if ErrorEvent=eeAccept then memo1.lines.add(inttostr(ding.port)+'  '+'A problem occurred when trying to accept a client connection request.');
  poin.Enabled:=true;
end;

procedure TForm1.poinTimer(Sender: TObject);
var a,b:integer;
begin
  ding.Active:=false;
  a:=ding.port;
  if a<strtoint(edit2.text) then inc(a);
  ding.port:=a;
  b:=strtoint(edit2.text)+1;
  if a>=b then ding.Active:=true;

  poin.Enabled:=false;
end;

procedure TForm1.dingRead(Sender: TObject; Socket: TCustomWinSocket);
var a:string;
begin
  a:=socket.ReceiveText;
  memo1.lines.add('text'+a);
end;

end.
0
 
God_AresCommented:
so how about it??
0
 
RadlerCommented:
Listening...
0
 
nricoCommented:
I don't know what Delphi version you are using, but this works just fine for me:
(I have not included the definition, only the declaration)

Procedure TForm1.Form1Create(Sender:TObject);
Begin
  Application.OnException:=overrideException;
End;

Procedure TForm1.overrideException(Sender:TObject;E:Exception);
Begin
  If Pos('10048',E.Message)<>0 Then
    Application.MessageBox('Port is already in use','MyProgram Error',MB_ICONSTOP Or MB_OK)
  Else
    Application.MessageBox(PChar(E.Message),'MyProgram Error',MB_ICONSTOP Or MB_OK);
End;

Procedure TForm1.Button1Click(Sender:TObject);
Begin
  ServerSocket1.Port:=5000; // Or whatever you wish
  ServerSocket1.Listen;
End;

This piece of code will give you an error if port 5000 is already in use, and else it'll listen on port 5000.
With my Delphi 4, this works perfectly!

P.S: The 10048 is just the errorcode you'll get from the TServerSocket. I check if it's in the message; if so, the port is occupied.
0
 
bryan7Author Commented:
sorry for the long delay.. I'm still testing..
I'll try both things.. about dv I have Delphi 3.0 client/server but I use fpiette's twsocket..

brb.. thanks
0
 
nricoCommented:
Well, that could explain why you don't get the exception. I tested it with the native TCP/IP components of Delphi 4.
0
 
bryan7Author Commented:
k, this happened:

god_ares solution:
it worked.. giving different error numbers depending if port was listenning or already connected.. but I can't use that because it could leave in an inoperable state the app that is listenning.. let's suppose a program is listenning for the client on port 20000, once the client connects and disconnects the app will not listen again, ok using the proposed solution would could
leave the app not listenning.. I need something that doesn't interfere in any app that's listenning..

nrico's solution:

my app uses twsocket listenning on port x, using addr= 0.0.0.0
when I try tserversocket to listen I don't get any error.. it seems to be listenning..
then I try to connect the client.. and it connects to the demo with tserversocket in stead of my app with twsocket..

in stead.. if I use 'localhost' in stead of '0.0.0.0' for twsocket to listen, the demo with serversocket gives an error..    what's happening ?

0
 
God_AresCommented:
that's should not be possible. The program uses the 3 way handshake.. if it does'nt do this then, and only than could a port quit listening.
0
 
bryan7Author Commented:
? I don't understand your last comment..


ain't there any function or something to check if a port is being used without having to do all this checking stuff ?
0
 
bryan7Author Commented:
sorry again for my delay.. don't think i forgot about this q. i'll be back later
0
 
God_AresCommented:
k cool... i have checked with a programmer from cute ftp server and they are doing it like me.. i'll write some aditional code 4 u... (couze i'm bored :-}  )

thanx 4 tha comment
0
 
bryan7Author Commented:
Adjusted points from 100 to 200
0
 
bryan7Author Commented:
umm some code.. great !
umm i was so busy lately i was working to get some money and didn't make much programming.

i double the points for the long delay.. I'll try the code now
0
 
God_AresCommented:
http://www.angelfire.com/ok/GODARES/downl.html

get portx.zip

open the exe on time, and see what happens... then open it for a seccond time...
0
 
God_AresCommented:
you should make somting like this

make the clientsocket.onconnect := (procedure)  i don't know how.  perhaps you can explain this to me.

Function LocateUnusedTCPPort(StartAt, EndAt : Integer) : Integer;

var
  ClientSocket : TClientSocket;
  free : integer;

procedure ClientSocketError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  errorcode:=0;
  free := 1;
end;

procedure ClientSocketConnect(Sender: TObject;
  Socket: TCustomWinSocket); TSocketNotifyEvent;
begin
  free:=0;
end;


begin
  ClientSocket := TClientSocket.Create(Nil);
  free:=-1;
  try
    ClientSocket.Address := '127.0.0.1'; {SKIP}
    ClientSocket.Host := '127.0.0.1'; {SKIP}
    ClientSocket.Port := StartAt - 1;

//    Clientsocket.OnConnet
    ClientSocket.OnConnect := ClientSocketConnect;

    Repeat
      ClientSocket.Port := ClientSocket.Port + 1;
      Result := ClientSocket.Port;
      ClientSocket.active:=true;
      repeat until (free<>-1)
    Until (free=1) or (ClientSocket.Port = EndAt);

  finally
    ClientSocket.Free;
  end;
end;
0
 
EpsylonCommented:
I've created a demo project that lists all used ports:

http://eps.yi.org/download.asp?file=WSPorts.zip

I got the idea from the TCPSTAT program from Crits Vadim, which is included in the zip file.


However I still prefer to use some code like this to find an unused port:

procedure TForm1.FormCreate(Sender: TObject);
const
  FIRSTPORT = 6000;
  LASTPORT  = 6999;
var
  port: Integer;
  connected: Boolean;
begin
  Memo1.Clear;
  port := FIRSTPORT;
  repeat
    try
      ServerSocket1.Port := port;
      ServerSocket1.Active := true;
      Memo1.Lines.Add('Listening on port ' + IntToStr(port));
      connected := true;
    except
      Inc(port);
      connected := false;
    end;
  until connected or (port > LASTPORT);
  if port > LASTPORT then
    Memo1.Lines.Add('No port available');
end;
0
 
EpsylonCommented:
Awfully quiet out here...
0
 
God_AresCommented:
This question has been up since
4/22/00,

so Bryan7, when are you going to grade this question?

your question has been answerd by me and by Epsylon... both of us gave you good sample code.

0
 
bryan7Author Commented:
well finally I'm active again into delphi.

I tried God_ares solutions again and they always give me some winsock error. it only works if there's a socketserver LISTENNING. but what happens if...

app A is listenning on port 6000
app B connects to it on port 6000

now app A associates this connection to a client so app A is not listenning anymore.
now there is a stablished connection between these 2 apps.

TCP    127.0.0.1:1026         127.0.0.1:6000        ESTABLISHED

TCP    127.0.0.1:6000        127.0.0.1:1026         ESTABLISHED


at this point God_Ares solution didn't work.

I tried your code Epsylon, and also didn't work.. but... WSPorts works great ! it lists all the ports being used at the point said before..

I will give this 200 points with A grade to god_ares for all the tries and time spent with me..  a million thanks, and sorry sorry sorry for not being able to test this before.


about Epsylon.. i will give you another 200p.
can i use your code (wsports) in my apps ?
and if they get commercial ?
0
 
God_AresCommented:
duh.. your server socket can cope with more than 1 connection. If you wrote a webserver your serversocket would listen on port 80 right?.. and if you would check with netstat is a connection was made you would see

x.x.x.x   listening

and when 1 client would connect you would see

x.x.x.x   ESTABLISHED

but don't you think you would make your serversocket can handle more than 1 connection??? if that wasn't possible how do sites like microsoft.com handle all it's connections?

understand?
0
 
bryan7Author Commented:
uh i don't want my server to have more than 1 conn..
it listens and once a clienc connects the another socket gets the connection and the server stops
0
 
God_AresCommented:
well then if you are using my solution you should disconnect after connect. this only will take a sec and it is 4 initialisation.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.