I've created a thread that checks if a port is opened or closed. After running 753 times i get "Thread error: The handle is invalid (6)". What am I doing wrong? I've tested it against 50 ports and haven't had a problem. Now I try to check 65536 ports on my local ip an I get this error after the 731 port. Thank you!
Here is the thread code:
{==============================START THREAD VERIFICARE PORT PRIN EXTRAGERE NUME HOST,IP,PORT============================================}
function elimina_toate_spatiile_goale(const s: string): string;
var
i, j: Integer;
begin
SetLength(Result, Length(s));
j := 0;
for i := 1 to Length(s) do begin
if not TCharacter.IsWhiteSpace(s[i]) then begin
inc(j);
Result[j] := s[i];
end;
end;
SetLength(Result, j);
end;
function Parse2(str: String; delimiter: Char; param_num: Integer): String;
var
c, x, y : LongInt;
begin
x := 1; // param number that we're currently 'in'
y := 0; // position of previous delimiter
for c := 1 to Length(str) do
if str[c] = delimiter then // this char is a delimiter
begin
if x = param_num then
Break;
inc(x);
y := c;
end;
if x = param_num then
Result := Copy(str, y + 1, c - y - 1)
else
Result := '';
end;
type
TThread_extrage_hostname_ip_si_port = class(TThread)
private
fStringul_ce_trebuie_parsat: string;
fHostname,fIP_de_verificat,fPort_de_verificat,fIP_si_port:string;
REZULTAT_verificare_port:BOOLEAN;
flistbox_porturi_online,flistbox_porturi_offline:Tlistbox;
fmemo_loguri:Tmemo;
procedure semnalizare_port_online_sau_offline;
protected
procedure Execute; override;
public
constructor Create(aStringul_ce_trebuie_parsat: string;alistbox_porturi_online,alistbox_porturi_offline:Tlistbox;amemo_loguri:Tmemo);
end;
constructor TThread_extrage_hostname_ip_si_port.Create(aStringul_ce_trebuie_parsat: string;alistbox_porturi_online,alistbox_porturi_offline:Tlistbox;amemo_loguri:Tmemo);
begin
inherited Create(False);
freeonterminate:=true;
fStringul_ce_trebuie_parsat:=aStringul_ce_trebuie_parsat;
flistbox_porturi_online:= alistbox_porturi_online;
flistbox_porturi_offline:= alistbox_porturi_offline;
fmemo_loguri:= amemo_loguri;
end;
procedure TThread_extrage_hostname_ip_si_port.Execute;
var
IdTCPClient : TIdTCPClient;
begin
// use fURL, fMethod, and fParam as needed...
REZULTAT_verificare_port := False;
fhostname:=(Parse2(fStringul_ce_trebuie_parsat,'=', 1));
fIP_si_port:=elimina_toate_spatiile_goale(Parse2(fStringul_ce_trebuie_parsat,'=', 2));
fIP_de_verificat:=elimina_toate_spatiile_goale(Parse2(fIP_si_port,':', 1));
fPort_de_verificat:=elimina_toate_spatiile_goale(Parse2(fStringul_ce_trebuie_parsat,':', 2)) ;
if (fIP_de_verificat<>'') and (fport_de_verificat<>'') then begin
try
IdTCPClient := TIdTCPClient.Create(nil);
try
IdTCPClient.Host := fIP_de_verificat;
IdTCPClient.Port := strtoint(fPORT_de_verificat);
IdTCPClient.ConnectTimeout:=5000;
IdTCPClient.Connect;
REZULTAT_verificare_port := True;
finally
IdTCPClient.Free;
end;
except
//Ignore exceptions
end;
Synchronize(semnalizare_port_online_sau_offline);
end;
end;
procedure TThread_extrage_hostname_ip_si_port.semnalizare_port_online_sau_offline;
begin
if REZULTAT_verificare_port=true then
begin
{verific daca in listbox-ul pentru porturi online exista deja elementul testat.
Daca elementul nu exista, il adaug.
Daca exista deja, nu il mai adaug.
}
if fListBox_porturi_online.Items.IndexOf(fStringul_ce_trebuie_parsat) = -1 then
begin
fmemo_loguri.lines.add(datetimetostr(now)+' - '+fStringul_ce_trebuie_parsat +' => ACTIV');
fListBox_porturi_online.Items.Add(fStringul_ce_trebuie_parsat);
end;
Form2.GroupBox_porturi_online.Caption:='PORTURI ONLINE: '+inttostr(fListBox_porturi_online.Items.Count);
end
else
begin
{verific daca in listbox-ul pentru porturi online exista deja elementul testat.
Daca elementul nu exista, il adaug.
Daca exista deja, nu il mai adaug.
}
if fListBox_porturi_offline.Items.IndexOf(fStringul_ce_trebuie_parsat) = -1 then
begin
fmemo_loguri.lines.add(datetimetostr(now)+' - '+fStringul_ce_trebuie_parsat +' => OPRIT');
fListBox_porturi_offline.Items.Add(fStringul_ce_trebuie_parsat);
end;
end;
Form2.GroupBox_porturi_offline.Caption:='PORTURI OFFLINE: '+inttostr(fListBox_porturi_offline.Items.Count);
end;
{==============================STOP THREAD EXTRAGERE NUME HOST,IP,PORT============================================}
A wild guess.
// ........ CODE ABOVE REMOVED
IdTCPClient.Connect;
REZULTAT_verificare_port := True;
finally
if IdTCPClient.connected then // ADD SOMETHING LIKE THIS SECTION ?
begin
IdTCPClient.IOHandler.InputBuffer.clear;
IdTCPClient.Disconnect;
end;
IdTCPClient.Free;
// ........ CODE BELOW REMOVED
If this fixes it then the problem is that a single process can only have around 731 open sockets at once using the APIs you are using.
Alternatively maybe the system you are connecting to also has limits on the total number of open sockets (it can receive) simultaneously?
Either way you are hit a system limit somewhere.
...
UPDATE due to your comment.
Threads have resource limits too. You can not create unlimited threads (like you can not create unlimited TCP sockets). Can you use a thread-safe counter and ensure you stop creating threads when you hit 100 threads, until one of the previous thread exit.
Now you can create this yourself with a basic sleep()/wait()/synchronize() like in Java. You have a method that only returns when it increments (it will wait as needed, until it can increment) and another method that always decrements.
Now you may find your main thread can not sleep for other reasons, some systems need to call API to reap the dead/exited threads, before the threads resources are really freed up. In this case you decrement by one when the resource is available, not at the point of the thread execution ended.
Even 100 threads running your code will run very fast, you may find that if you limit the number of threads to between the number of core and double the number of cores in your system, that you can make the whole thing faster (if the tasks are CPU bound).
Since 100 threads active on a 8 core system, is not as efficient as 16 threads active on an 8 core system. However a lot of your process time will be dominated by waiting for network connection delays. So 16 thread will not be enough.
This pattern is often call a semaphore (with counter). Google hit for "delpi semaphore threading" http://edn.embarcadero.com/article/29908