Delphi simple TCP server hangs. The form is frozen, but the server continues to manage clients
I am using a form with IdTCPServer which manages lines from the client using the AThread.connection.readln / writeln system. Row processing works and it is not a problem.
The thing is, the form with the server on it hangs and doesn't load, but it still manages all the clients connected to it, so it works, but it just doesn't work like a form. I'll make the assumption that its sitting on a readline or whatever ... but I have no idea how I can fix this at this point in time.
Please, help.
procedure TMonitorFrm.ServerExecute(AThread: TIdPeerThread);
procedure post(PostMessage:string);
begin
try
AThread.Connection.WriteLn(PostMessage);
except
showmessage('Cannot post');
end;
end;
var
ActClient : PClient;
sTemp,
CommBlock,
NewCommBlock,
ReceiverName,
sContent,
sSQL,
sCommand : String;
iCount2,
iCount : Integer;
sldb : TSQLiteDatabase;
sltb : TSQLiteTable;
begin
if not AThread.Terminated and AThread.Connection.Connected then
begin
CommBlock := AThread.Connection.ReadLn();
ActClient := PClient(AThread.Data);
ActClient.LastAction := Now;
sCommand := copy(CommBlock,0,pos(',',CommBlock)-1); {seperate command}
sContent := copy(CommBlock,pos(',',CommBlock)+1,length(CommBlock)-(pos(',',CommBlock)+1)); {seperate data block}
iCount:= 0 ;
if sCommand = 'Announce' then //SPECIAL
begin
{ Do stuff for this command...}
end
else if sCommand = 'CheckSect' then
{Etcetera...}
procedure TMonitorFrm.FormCreate(Sender: TObject);
var
sCompetitionID : string;
sldb : TSQLiteDatabase;
sltb : TSQLiteTable;
begin
Clients := TThreadList.Create;
Server.Active := True;
AreaPnlList := TComponentList.Create;
SectionPnlList := TComponentList.Create;
Repeat until InputQuery('Competition Select', 'Please type the ID of the competition', sCompetitionID);
iCompetitionID:=StrToInt(sCompetitionID);
OpenDatabase(slDb);
sltb:=slDb.GetTable('SELECT * FROM SectionTable WHERE CompetitionID='+sCompetitionID);
Frame31.CreateSections(sltb,Frame31);
sltb.Free;
CloseDatabase(slDb);
{
This section needs to check the SQLite databases for sections and list them in the display window and makes a drag n drop profile...
}
end;
a source to share
Here's how to stop Readln by making it freeze. You need to check if there is something there to read. There are several ways to do this, you can make readln timeout
Repeat
CommBlock := '';
CommBlock := AThread.Connection.ReadLn('',10);
Application.ProcessMessages;
until Commblock <> '';
Or you can check if the connection is readable before reading the text.
Repeat
CommBlock:='';
if AThread.Connection.IOHandler.Readable()then
begin
CommBlock := AThread.Connection.ReadLn();
end
else
begin
application.ProcessMessages;
end;
until commblock <> '';
The key line is Application.ProcessMessages anyway, as this allows the main thread to check its messages and keep running.
a source to share
Indy uses blocking sockets. He needs to hang the current thread. To use Indy components in a VCL thread while maintaining VCL responsiveness, add the component TIdAntifreeze
to the form. Indy components are aware of this component and periodically monitor it so that the VCL thread can continue processing messages.
a source to share
If you think you cannot reliably track execution with the debugger, you can add explicit tracing information to your code .
Use OutputDebugString
to log information to either the IDE's EventLog when run from the IDE, or the DbgView (from SysInternals) when working outside of Delphi.
a source to share
Remember that VCL components are not thread-safe, so you cannot access them directly from a thread, otherwise something will go wrong, for example, the main thread may get stuck.
So check that TMonitorFrm.ServerExecute does nothing with forms and components. If you need to update something, use Synchronize.
a source to share