Delphi简单的TCP服务器挂起。表单冻结但服务器继续管理客户端

时间:2010-04-22 21:04:42

标签: delphi tcp

我正在使用带有IdTCPServer的表单来管理来自客户端的字符串,其中包含AThread.connection.readln / writeln系统。字符串处理有效,这不是问题。

问题是,服务器上的表单挂起并且不会加载,但它仍然管理连接到它的所有客户端,因此它正在运行,但它不能用作表单。 我会猜测它是坐在阅读线上还是什么东西......但是我不知道如何在这个时刻解决这个问题。

请帮忙。

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;

4 个答案:

答案 0 :(得分:6)

Indy使用阻塞套接字。 假定挂起当前线程。要在VCL线程中使用Indy组件同时保持VCL线程响应,请在表单上放置TIdAntifreeze组件。 Indy组件知道该组件并定期对其进行控制,以便您的VCL线程可以继续处理消息。

答案 1 :(得分:4)

如果您认为无法使用调试器可靠地跟踪执行情况,则可以在代码中添加一些显式跟踪信息
使用OutputDebugString在从IDE运行时在IDE EventLog中记录信息,或者在Delphi外部运行时记录 DbgView窗口(来自SysInternals)

答案 2 :(得分:0)

请记住,VCL组件不是线程安全的,因此您无法直接从线程访问它们,否则会出现问题,例如主线程可能会卡住。

因此,请检查TMonitorFrm.ServerExecute是否对表单和组件不执行任何操作。如果您需要更新某些内容,请使用Synchronize。

答案 3 :(得分:0)

这是停止Readln导致它冻结的方法。你需要检查是否有东西可以先阅读。有几种方法可以做到这一点,你可以进行readln超时

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

或者您可以在尝试阅读之前检查连接是否可读。

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

无论哪种方式,关键行都是Application.ProcessMessages,因为这允许主线程检查其消息并继续运行。