tags:

views:

136

answers:

4

I'm using a form with an IdTCPServer on it managing strings from the client with a AThread.connection.readln/writeln system. The string handling works and that isn't the problem.

The thing is, the form with the server on it hangs and will not load, but it still managed all the clients connected to it so it IS running but it just doesn't work as a form. I'll make a guess that its sitting on a readline or something... but I have NO idea how i can fix this at this moment 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;
+3  A: 

If you think you cannot reliably trace the execution with the debugger, you can add some explicit trace information in your code.
Use OutputDebugString to log information either in the IDE EventLog when running from the IDE or to a DbgView window (from SysInternals) when running outside Delphi.

François
wow, these look interesting. Thanks and i'll go look up how to use them and get back to you.
NeoNMD
This is actually very useful, thanks for this. It has shown it is hanging on the readln. Unfortunately I still dont know how to fix this.
NeoNMD
+6  A: 

Indy uses blocking sockets. It's supposed to hang the current thread. To use Indy components in the VCL thread while keeping the VCL thread responsive, put a TIdAntifreeze component on the form as well. The Indy components are aware of that component and will yield control to it periodically so that your VCL thread can continue processing messages.

Rob Kennedy
I'm afraid to report that TIdAntiFreeze has not changed anything at all. Its still frozen. I did an OutputDebugString at the start of the server execute and it DOES infact trigger it on connect and then not trigger any subsequent OutputDebugStrings so it must be blocked there somehow. I'll experiment further.
NeoNMD
If you're wondering where it's blocked, there's no need to guess or trace. Simply press the "pause" button in the debugger. Then look at the call stacks, and you'll see *exactly* where each thread was running.
Rob Kennedy
Its stuck on the readln near the top of the server execute. That is where it is stuck.
NeoNMD
It is supposed to be. Like Rob said, Indy uses blocking sockets. The ReadLn() is blocking the OnExecute thread waiting for the client to actually write a line.
Remy Lebeau - TeamB
A: 

Remember that VCL components are not thread safe, so you cannot access them directly from thread, otherwise something will go wrong, eg main thread can get stuck.

So check that TMonitorFrm.ServerExecute doesn't do anything with forms and components. If you need to update something, use Synchronize.

Harriv
This sounds promising. How would I go about using synchronise in my case?
NeoNMD
What kind of VCL usage you have inside the thread?
Harriv
It basically has a couple of forms and each form has panels on it. I just want the form viewable as the data on the panels changed as the server runs. Also I need to make a drag and drop on the panels at a later time as one of the things a client can ask for is one of the section ID's and that could be passed via drag and drop.
NeoNMD
A: 

This is how to stop the Readln causing it to freeze. You need to check if there is something there to read first. There are a couple ways to do this, you can make the readln timeout

Repeat
    CommBlock := '';
    CommBlock := AThread.Connection.ReadLn('',10);
    Application.ProcessMessages;
until Commblock <> '';

Or you can check if the connection is readable before tryign to read.

Repeat
    CommBlock:='';
    if AThread.Connection.IOHandler.Readable()then
    begin
            CommBlock := AThread.Connection.ReadLn();
    end
    else
    begin
            application.ProcessMessages;
    end;
until commblock <> '';

Either way, the key line is Application.ProcessMessages as this allows the main thread to check its messages and keep running.

NeoNMD
Do not call ProcessMessages() outside of the thread main thread. It is not thread-safe.
Remy Lebeau - TeamB
That may be true but at the moment it is the only thing that makes it work. Is there some equivalent to ProcessMessages that has the same effect?
NeoNMD