I have two processes that must run on two free TCP ports on the PC. This must be a painless out-of-the-box process for it's user, I want to auto detect free ports to avoid conflicts and apply these port numbers to these two processes.
To achieve this, I made a function (that runs in a thread also) to detect the free ports but doesn't find any free ports. Can somebody explain what is wrong with my code?
EDIT: The solution provided by "@500-error etc" is applied to the code. Function now working OK.
Here it is:
uses
winsock;
type
TAvailablePortArray = array of Word;
function findAvailableTCPPort( ipAddressStr : String; portStart : Word = 8080; portEnd : Word = 8084; findCount : Byte = 2 ) : TAvailablePortArray;
var
client : sockaddr_in;
sock : Integer;
ret : Integer;
wsdata : WSAData;
dwPort : Word;
iFound : Byte;
bResult : Boolean;
bAllFound : Boolean;
dns : PHostEnt;
status : LongInt;
begin
setLength( Result, 0 );
if( portStart > portEnd ) or ( portStart = 0 ) or ( findCount = 0 ) then
Exit;
try
ret := WSAStartup($0002, wsdata); //initiates use of the Winsock DLL
except
ret:=-1;
end;
if( ret <> 0 ) then
Exit;
dns:=getHostByName( PChar(ipAddressStr) );
if( NOT Assigned( dns )) then
Exit;
bResult:=TRUE;
try
fillChar( client, sizeOf( client ), 0 );
client.sin_family := AF_INET; //Set the protocol to use , in this case (IPv4)
client.sin_addr.s_addr :=LongInt(PLongInt(dns^.h_addr_list^)^);
//inet_addr(PAnsiChar(ipAddressStr)); //convert to IN_ADDR structure
except
bResult:=FALSE;
end;
if( bResult ) then
begin
dwPort:=portStart;
setLength( Result, findCount );
bAllFound:=FALSE;
iFound:=0;
while( NOT bAllFound ) and ( dwPort <= portEnd ) do
begin
try
client.sin_port:=htons(dwPort); //convert to TCP/IP network byte order (big-endian)
sock:=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP ); //creates a socket
Application.processMessages();
status:=connect(sock,client,sizeOf(client));
bResult:=(status <> 0); //establishes a connection to a specified socket, less than zero is NOT in use
except
bResult:=FALSE;
end;
if( sock <> 0 ) then
begin
closesocket(sock);
sock:=0;
end;
if( bResult ) then
begin
Result[iFound]:=dwPort;
inc( iFound );
bAllFound:=( iFound = findCount );
end;
inc(dwPort);
end;
end;
if( NOT bAllFound ) then
setLength( Result, 0 );
try
WSACleanup();
except;
end;
end;
Some code to call the function above:
procedure TForm1.btStartClick(Sender: TObject);
begin
addLogMsg( 'Starting service ...' );
FPorts:=findAvailableTCPPort( '127.0.0.1' );
FPortCount:=Length( FPorts );
addLogMsg( 'Available ports found: '+strToInt( FPortCount ));
if( FPortCount < 2 ) then
begin
addLogMsg( 'ERROR: Cannot start service(s), insufficient free ports!' );
Exit;
end;
................
................
................
end;
What I am doing wrong?
NOTE: I have debug the code, the process seems to be OK (it tries to test it, no exceptions). Also verified that the ports specified are not in use by testing it with other app.
I (now) believe the issue is that you are misinterpreting the result from connect
.
If connect
succeeds (returns zero), it means that the port is in use.