2017-01-26 25 views
0

최신 Raspbian이로드 된 Ribberry PI에서 Indy 10.6 tcpserver를 사용하여 새 시스템을 설정하고 있습니다. 나는 sudo가있는 터미널 bash 스크립트를 통해 GUI 데스크탑에서 응용 프로그램을 실행 중입니다. 클라이언트가 연결될 때까지 모든 것이 잘 작동하고 연결이 끊어지면 Gtk-WARNINGs가 나오고 Gtk-CRITICALs가 나오고 그 이유를 모르겠습니다. 여기 내 코드는 한 번에 하나 개의 클라이언트 연결이 다음 서버를 비활성화 할 수 있으며 각 연결 완료 후 다시 시작이야 :Indy 10.6 관리자 권한이있는 Linux 시스템에서 tcpserver를 사용하면 클라이언트 연결이 끊어지면 Gtk-WARNING이 발생합니다.

Procedure TFK20Elevator.ASpeedBtn1Click(Sender: TObject); 
Begin //start the server 
    Server.Active := False; 
    Server.Bindings.Clear; 
    Server.Bindings.Add.IPVersion := Id_IPv4; 
    Server.Bindings.Add.IP := LIP; 
    Server.Bindings.Add.Port := DefPort + StrToIntDef(UnitID, 0); 
    Try 
    Server.Active := True; 
    Except 
    On E: Exception Do 
     Memo1.Lines.Add(E.Message); 
    End; 
    If Not Server.Active Then 
    Exit; 
    ASpeedBtn1.Enabled := False; 
    ASpeedBtn2.Enabled := True; 
    AStatus1.SimpleText := 'Server bound to ' + LIP + ':' + IntToStr(DefPort + StrToIntDef(UnitID, 0)); 
End; 

Procedure TFK20Elevator.ServerConnect(AContext: TIdContext); 
Begin 
    If Connected Then 
    Begin 
     Abort(); 
     Exit; 
    End; 
    AStatus1.SimpleText := 'Connecting to> ' + AContext.Binding.PeerIP + ' - Authenticating...'; 
    Memo1.Lines.Clear; 
    Manager := False; 
    EncDecSIdx := 1; 
    RetryTimer.Enabled := False; 
    RetryTimer.Interval := 3000; 
    Authenticating := True; 
    AuthTimer.Enabled := True; 
    StayAlive.Enabled := True; 
End; 

Procedure TFK20Elevator.ServerException(AContext: TIdContext; AException: Exception); 
Begin 
    If AnsiContainsText(AException.Message, 'Gracefully') Then 
    AStatus1.SimpleText := 'Server bound to ' + LIP + ':' + IntToStr(DefPort + StrToIntDef(UnitID, 0)) //closed gracefully message 
    Else 
    Begin //show the exception 
     Memo1.Lines.Add('An exception happend! - ' + AException.Message); 
     RetryTimer.Enabled := True; 
    End; 
    Manager := False; 
    Authenticating := False; 
End; 

Procedure TFK20Elevator.ServerExecute(AContext: TIdContext); 
//EncStr and DecStr simply encode/decode, respectively, a standard 
// string into/from a key encrypted hex string, i.e. '00' to 'FF' 
// for each character in the string 
Var 
    S, UserName, Password: String; 
    I, N: Integer; 
Begin 
    S := AContext.Connection.IOHandler.ReadLn(IndyTextEncoding_OSDefault, IndyTextEncoding_OSDefault); //get the data 
    If S = Heart Then //if message is the client heart beat, return to client 
    Begin //just a heart beat, reset timer 
     StayAlive.Enabled := False; 
     AContext.Connection.IOHandler.WriteLn(Heart, IndyTextEncoding_OSDefault, IndyTextEncoding_OSDefault); 
     StayAlive.Enabled := True; 
     Exit; 
    End; 
    S := PCommon.DecStr(S, EncDecStr, EncDecSIdx); //not heart beat, decompress 
    If Authenticating Then 
    Begin //test log in 
     If Length(S) > 3 Then 
     Begin 
      I := Pos('|', S); 
      If (I > 1) And (Length(S) > I) Then 
      Begin 
       UserName := Copy(S, 1, I - 1); 
       Password := Copy(S, I + 1, Length(S) - I); 
       If UserName = ManUser Then 
       Begin 
        If Password = ManPass Then 
        Begin 
         AuthTimer.Enabled := False; 
         Manager := True; 
         Authenticating := False; 
         AContext.Connection.IOHandler.WriteLn(EncStr(AContext.Binding.PeerIP + 
                  ':' + IntToStr(DefPort + StrToIntDef(UnitID, 0)) + 'M', 
                  EncDecStr, EncDecSIdx), IndyTextEncoding_OSDefault, 
                  IndyTextEncoding_OSDefault); 
         AStatus1.SimpleText := 'Connecting to> ' + AContext.Binding.PeerIP + ' as Manager'; 
         Connected := True; 
        End 
        Else 
        AuthTimerTimer(Self); 
       End 
       Else If UserName = GenUser Then 
       Begin 
        If Password = GenPass Then 
        Begin 
         AuthTimer.Enabled := False; 
         Authenticating := False; 
         AContext.Connection.IOHandler.WriteLn(EncStr(AContext.Binding.PeerIP + 
                  ':' + IntToStr(DefPort + StrToIntDef(UnitID, 0)) + 'U', 
                  EncDecStr, EncDecSIdx), IndyTextEncoding_OSDefault, 
                  IndyTextEncoding_OSDefault); 
         AStatus1.SimpleText := 'Connecting to> ' + AContext.Binding.PeerIP + ' as General User'; 
         Connected := True; 
        End 
        Else 
        AuthTimerTimer(Self); 
       End 
       Else 
       AuthTimerTimer(Self); 
      End 
      Else 
      AuthTimerTimer(Self); 
     End 
     Else 
     AuthTimerTimer(Self); 
    End 
    Else 
    Begin //test for commands 
     If Copy(S, 1, Length(AssignID)) = AssignID Then 
     Begin //command to assign a new unit id 
      NewLoc := DefLocation; 
      NewUnit := DefUnitNum; 
      I := Pos('-', S, 1); 
      If (I > 0) And (I < Length(S)) Then 
      Begin 
       N := Pos('-', S, I + 1); 
       If (N > 0) And (N < Length(S)) Then 
       Begin 
        NewLoc := Copy(S, I + 1, N - I - 1); 
        NewUnit := Copy(S, N + 1, Length(S) - N); 
       End; 
      End; 
      Label15.Caption := NewLoc; 
      Label16.Caption := NewUnit; 
      FmtStr(LIP, '%.3d', [StrToInt(NewUnit)]); 
      LIP := '192.168.6' + Copy(LIP, 1, 1) + '.' + Copy(LIP, 2, 2); //wifi ip 
      Memo1.Lines.Add('--> ' + S + '-' + LIP); 
      AContext.Connection.IOHandler.WriteLn(PCommon.EncStr(Rebooting, EncDecStr, EncDecSIdx), 
               IndyTextEncoding_OSDefault, IndyTextEncoding_OSDefault); 
      Memo1.Lines.Add('<-- ' + Rebooting); 
      TestTimer.Enabled := True; 
     End; 
    End; 
End; 

Procedure TFK20Elevator.ASpeedBtn2Click(Sender: TObject); 
Begin //shut down the server with optional restart if not rebooting 
    AuthTimer.Enabled := False; 
    RetryTimer.Enabled := False; 
    StayAlive.Enabled := False; 
    TestTimer.Enabled := False; 
    DropClient; 
    Try 
    Server.Active := False; 
    Except 
    On E: Exception Do 
     Memo1.Lines.Add('Error disconnecting server - ' + E.Message); 
    End; 
    If Server.Active Then 
    Exit; 
    ASpeedBtn1.Enabled := True; 
    ASpeedBtn2.Enabled := False; 
    AStatus1.SimpleText := 'Server not running...'; 
    Manager := False; 
    Authenticating := False; 
    Connected := False; 
    RetryTimer.Enabled := Not SysReboot; 
End; 

Procedure TFK20Elevator.ServerDisconnect(AContext: TIdContext); 
Begin 
    StayAlive.Enabled := False; 
    RetryTimer.Enabled := False; 
    DropClient; 
    AStatus1.SimpleText := 'Client disconnected...'; 
    Manager := False; 
    Authenticating := False; 
    Connected := False; 
    RetryTimer.Enabled := Not SysReboot; 
End; 

Procedure TFK20Elevator.DropClient; //make sure buffers are cleared 
Var 
    I: Integer; 
    SC: TIdContext; 
Begin 
    If Server.Active Then 
    Begin 
     Application.ProcessMessages; 
     With Server.Contexts.LockList Do 
     Try 
      Memo1.Lines.Add('Disconnecting...'); 
      For I := Count - 1 DownTo 0 Do 
      Begin 
       SC := TIdContext(Items[I]); 
       If SC = Nil Then 
       Continue; 
       SC.Connection.IOHandler.WriteBufferClear; 
       SC.Connection.IOHandler.InputBuffer.Clear; 
       SC.Connection.IOHandler.Close; 
       If SC.Connection.Connected Then 
       SC.Connection.Disconnect; 
       Memo1.Lines.Add('Disconnecting client ' + IntToStr(I + 1) + ' of ' + IntToStr(Count)); 
      End; 
     Finally 
      Server.Contexts.UnlockList; 
      Memo1.Lines.Add('Disconnected'); 
     End; 
    End; 
End; 

Procedure TFK20Elevator.StayAliveTimer(Sender: TObject); 
Begin //server reset timer if client stops sending heart beat 
    StayAlive.Enabled := False; 
    AStatus1.SimpleText := 'Client timed out!'; 
    If ASpeedBtn2.Enabled Then 
    ASpeedBtn2Click(Self); 
End; 

Procedure TFK20Elevator.AuthTimerTimer(Sender: TObject); 
Begin //login authorization timeout timer 
    AuthTimer.Enabled := False; 
    ASpeedBtn2Click(Self); 
    Application.ProcessMessages; 
    ASpeedBtn1Click(Self); 
End; 
+0

또한 Pango-CRITICALs를 많이 확보하십시오. ServerDisconnect에서 DropClient를 사용 불가능으로 설정하려고 시도했지만 도움이되지 않습니다. – user7475089

+0

메시지의 일부 : – user7475089

+0

Pango가-CRITICAL ** : pango_layout_get_context : 주장! '레이아웃 = NULL은' Pango가-CRITICAL 실패 ** : pango_context_get_language : pango_context_get_metrics : 주장 '! 문맥 = NULL은' Pango가-CRITICAL ** 실패 주장을 pango_font_metrics_get_approximate_char_width : pango_font_metrics_get_approximate_digit_width : 주장 '! 메트릭 = NULL은'** Pango가-CRITICAL 실패 'PANGO_IS_CONTEXT (컨텍스트)'** Pango가-CRITICAL 실패 '! 메트릭 = NULL이'주장 클라이언트 프로그램이 실제로 등 – user7475089

답변

0
Server.Bindings.Add.IPVersion := Id_IPv4; 
Server.Bindings.Add.IP := LIP; 
Server.Bindings.Add.Port := DefPort + StrToIntDef(UnitID, 0); 

이 코드에서 버그입니다. 당신은 1 개의 청취 소켓을 열지 않고 있으며, 실제로는 3 개의 청취 소켓을 열고 있습니다! Bindings.Add()을 호출 할 때마다 TIdTCPServer에 별도의 청취 소켓을 만들고 각 Binding 객체에는 고유 한 IP/포트 설정이 있습니다. 당신이 정말로 위의 코드로 뭐

은 다음과 같습니다 포트 TIdTCPServer.DefaultPort에 IP 0.0.0.0에 바인딩는 IPv4를 만들

  1. . (당신이 IdCompilerDefines.inc에 정의 IdIPv6와 인디 다시 컴파일하지 않는 한, IPv4의 될 일) 인디의 기본 IP 버전을 사용하여 다른 포트 TIdTCPServer.DefaultPort에 IP LIP에 바인딩을 만드는

  2. .

  3. Indy의 기본 IP 버전에 따라 DefPort+UnitID 포트의 0.0.0.0 또는 ::1에 또 다른 Binding을 만듭니다.

은 당신이하려고하는 것을 들어, 예를 들어, Bindings.Add()한 번 만 호출 할 필요가 :

말했다되고 그건
var 
    Binding : TIdSocketHandle; 

Binding := Server.Bindings.Add; 
Binding.IPVersion := Id_IPv4; 
Binding.IP := LIP; 
Binding.Port := DefPort + StrToIntDef(UnitID, 0); 

, TIdTCPServer는 다중 스레드 구성 요소입니다. 다양한 이벤트 (OnConnect, OnDisconnect, OnExecute, OnExceptionOnListenException)는 내부적으로 생성 된 작업자 스레드의 컨텍스트에서 TIdTCPServer으로 시작됩니다. 이벤트 처리기는 기본 UI 스레드의 컨텍스트 외부에서 UI 컨트롤에 직접 액세스합니다. 그것은 모든 종류의 문제를 일으키며 절대로해서는 안됩니다.

이벤트 핸들러가 UI에 액세스해야하는 경우, 그들은 같은 TThread.Synchronize() 또는 TThread.Queue(), 또는 인디 자신의 TIdSync 또는 TIdNotify 클래스, 또는 사용자가 선택한 다른 스레드 간 맞추지 메커니즘으로 메인 UI 스레드와 동기화해야합니다.

DropClient()으로 수동으로 클라이언트를 삭제하면 비즈니스가 수행되지 않는 컨텍스트에도 적용됩니다. 어쨌든 TIdTCPServer은 비활성화되는 동안 클라이언트를 수동으로 삭제할 필요가 없습니다. 말했다 모두와 함께

은 더 이런 식으로 뭔가를 시도 :

interface 

uses 
    Classes, Form, SysUtils, StdCtrls, ExtCtrls, Buttons, IdTCPServer, IdContext; 

type 
    TFK20Elevator = class(TForm) 
    Server: TIdTCPServer; 
    ASpeedBtn1: TSpeedButton; 
    ASpeedBtn2: TSpeedButton; 
    Memo1: TMemo; 
    AStatus1: TStatusBar; 
    AuthTimer: TTimer; 
    RetryTimer: TTimer; 
    StayAlive: TTimer; 
    TestTimer: TTimer; 
    ... 
    procedure ASpeedBtn1Click(Sender: TObject); 
    procedure ASpeedBtn2Click(Sender: TObject); 
    procedure StayAliveTimer(Sender: TObject); 
    procedure AuthTimerTimer(Sender: TObject); 
    procedure ServerConnect(AContext: TIdContext); 
    procedure ServerDisconnect(AContext: TIdContext); 
    procedure ServerException(AContext: TIdContext; AException: Exception); 
    procedure ServerExecute(AContext: TIdContext); 
    ... 
    private 
    DefPort: Integer; 
    UnitID: string; 
    Manager: Boolean; 
    Authenticating: Boolean; 
    EncDecSIdx: Integer; 
    ... 
    procedure DropClient; 
    procedure ConnectedNotify(const APeerIP: string); 
    procedure DisconnectedNotify; 
    procedure ErrorNotify(const AMessage: string); 
    procedure HeartNotify; 
    procedure ManagerLoggedInNotify(const APeerIP: string); 
    procedure GeneralUserLoggedInNotify(const APeerIP: string); 
    procedure FailedAuthNotify; 
    procedure RebootNotify(const Data: string); 
    ... 
    end; 

var 
    FK20Elevator: TFK20Elevator; 

implementation 

uses 
    IdGlobal, IdSync; 

const 
    Heart: string = ...; 
    AssignID: string = ...; 
    ... 

procedure TFK20Elevator.ASpeedBtn1Click(Sender: TObject); 
var 
    Binding: TIdSocketHandle; 
begin 
    //start the server 

    Server.Active := False; 
    Server.Bindings.Clear; 
    Binding := Server.Bindings.Add; 
    Binding.IPVersion := Id_IPv4; 
    Binding.IP := LIP; 
    Binding.Port := DefPort + StrToIntDef(UnitID, 0); 
    Server.MaxConnections := 1; 

    try 
    Server.Active := True; 
    except 
    on E: Exception do 
    begin 
     Memo1.Lines.Add('Error activating server - ' + E.Message); 
     Exit; 
    end; 
    end; 

    AStatus1.SimpleText := 'Server bound to ' + Binding.IP + ':' + IntToStr(Binding.Port); 

    ASpeedBtn1.Enabled := False; 
    ASpeedBtn2.Enabled := True; 
end; 

procedure TFK20Elevator.ASpeedBtn2Click(Sender: TObject); 
begin 
    //shut down the server with optional restart if not rebooting 

    AuthTimer.Enabled := False; 
    RetryTimer.Enabled := False; 
    StayAlive.Enabled := False; 
    TestTimer.Enabled := False; 

    try 
    Server.Active := False; 
    except 
    on E: Exception do 
    begin 
     Memo1.Lines.Add('Error deactivating server - ' + E.Message); 
     Exit; 
    end; 
    end; 

    Manager := False; 
    Authenticating := False; 

    AStatus1.SimpleText := 'Server not running...'; 
    ASpeedBtn1.Enabled := True; 
    ASpeedBtn2.Enabled := False; 

    RetryTimer.Enabled := not SysReboot; 
end; 

procedure TFK20Elevator.StayAliveTimer(Sender: TObject); 
begin 
    //client stopped sending heart beats 
    StayAlive.Enabled := False; 
    Memo1.Lines.Add('Client timed out!'); 
    DropClient; 
end; 

procedure TFK20Elevator.AuthTimerTimer(Sender: TObject); 
begin 
    //login authorization timeout 
    AuthTimer.Enabled := False; 
    Memo1.Lines.Add('Authentication timed out!'); 
    DropClient; 
end; 

procedure TFK20Elevator.DropClient; 
begin 
    with Server.Contexts.LockList do 
    try 
    if Count > 0 then 
     TIdContext(Items[0]).Connection.Disconnect;   
    finally 
    Server.Contexts.UnlockList; 
    end; 
end; 

type 
    TMyNotifyMethod = procedure(const AStr: string) of object; 

    TMyNotify = class(TIdNotify) 
    protected 
    FMethod: TMyNotifyMethod; 
    FStr: string; 
    procedure DoNotify; override; 
    public 
    class procedure NotifyStr(AMethod: TMyNotifyMethod; const AStr: string); 
    end; 

procedure TMyNotify.DoNotify; 
begin 
    FMethod(FStr); 
end; 

class procedure TMyNotify.NotifyStr(AMethod: TMyNotifyMethod; const AStr: string); 
begin 
    with Create do 
    begin 
    FMethod := AMethod; 
    FStr := AStr; 
    Notify; 
    end; 
end; 

procedure TFK20Elevator.ConnectedNotify(const APeerIP: string); 
begin 
    if not Server.Active then Exit; 
    AStatus1.SimpleText := 'Connecting to> ' + APeerIP + ' - Authenticating...'; 
    Memo1.Lines.Clear; 
    RetryTimer.Enabled := False; 
    RetryTimer.Interval := 3000; 
    AuthTimer.Enabled := True; 
    StayAlive.Enabled := True; 
end; 

procedure TFK20Elevator.DisconnectedNotify; 
begin 
    StayAlive.Enabled := False; 
    RetryTimer.Enabled := False; 

    if Server.Active then 
    begin 
    with Server.Bindings[0] do 
     AStatus1.SimpleText := 'Client Disconnected. Server bound to ' + IP + ':' + IntToStr(Port); 
    end; 

    RetryTimer.Enabled := Not SysReboot; 
end; 

procedure TFK20Elevator.ErrorNotify(const AMessage: string); 
begin 
    Memo1.Lines.Add('An exception happened! - ' + AMessage); 
    RetryTimer.Enabled := True; 
end; 

procedure TFK20Elevator.HeartNotify; 
begin 
    StayAlive.Enabled := False; 
    StayAlive.Enabled := True; 
end; 

procedure TFK20Elevator.ManagerLoggedInNotify(const APeerIP: string); 
begin 
    AuthTimer.Enabled := False; 
    AStatus1.SimpleText := 'Connecting to> ' + APeerIP + ' as Manager'; 
end; 

procedure TFK20Elevator.GeneralUserLoggedInNotify(const APeerIP: string); 
begin 
    AuthTimer.Enabled := False; 
    AStatus1.SimpleText := 'Connecting to> ' + APeerIP + ' as General User'; 
end; 

procedure TFK20Elevator.FailedAuthNotify; 
begin 
    //login authorization failed 
    AuthTimer.Enabled := False; 
end; 

procedure TFK20Elevator.RebootNotify(const Data: string); 
var 
    Tmp, S, NewLoc, NewUnit, LIP: string; 
begin 
    Tmp := Data; 

    S := Fetch(Tmp, #10); 
    NewLoc := Fetch(Tmp, #10); 
    NewUnit := Tmp; 

    Label15.Caption := NewLoc; 
    Label16.Caption := NewUnit; 

    FmtStr(LIP, '%.3d', [StrToInt(NewUnit)]); 
    LIP := '192.168.6' + Copy(LIP, 1, 1) + '.' + Copy(LIP, 2, 2); //wifi ip 

    Memo1.Lines.Add('--> ' + S + '-' + LIP); 
    Memo1.Lines.Add('<-- ' + Rebooting); 

    TestTimer.Enabled := True; 
end; 

procedure TFK20Elevator.ServerConnect(AContext: TIdContext); 
begin 
    Manager := False; 
    Authenticating := True; 
    EncDecSIdx := 1; 

    TMyNotify.NotifyStr(@ConnectedNotify, AContext.Binding.PeerIP); 

    // Note: OSDefault is platform-specific. On Linux, it is UTF-8, so 
    // you should use UTF-8 explicitly instead, so as to provide 
    // better compatibility across platforms, especially if you ever 
    // move this server code to another platform in the future... 
    // 
    AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_OSDefault; // IndyTextEncoding_UTF8 
    AContext.Connection.IOHandler.DefAnsiEncoding := IndyTextEncoding_OSDefault; // IndyTextEncoding_UTF8 
end; 

procedure TFK20Elevator.ServerDisconnect(AContext: TIdContext); 
begin 
    Manager := False; 
    Authenticating := False; 
    TIdNotify.NotifyMethod(@DisconnectedNotify); 
end; 

procedure TFK20Elevator.ServerException(AContext: TIdContext; AException: Exception); 
begin 
    if not (AException is EIdConnClosedGracefully) then 
    TMyNotify.NotifyStr(@ErrorNotify, AException.Message); 
end; 

procedure TFK20Elevator.ServerExecute(AContext: TIdContext); 
var 
    S, Tmp, UserName, Password: String; 
begin 
    S := AContext.Connection.IOHandler.ReadLn; //get the data 
    if S = Heart then 
    begin 
    //just a heart beat, return to client and reset timer 
    AContext.Connection.IOHandler.WriteLn(Heart); 
    TIdNotify.NotifyMethod(@HeartNotify); 
    Exit; 
    end; 

    //not heart beat, decompress 
    //EncStr and DecStr simply encode/decode, respectively, a standard 
    // string into/from a key encrypted hex string, i.e. '00' to 'FF' 
    // for each character in the string 

    S := PCommon.DecStr(S, EncDecStr, EncDecSIdx); 

    if Authenticating then 
    begin 
    //test log in 
    UserName := Fetch(S, '|'); 
    Password := S; 

    if (UserName = ManUser) and (Password = ManPass) then 
    begin 
     Authenticating := False; 
     Manager := True; 
     AContext.Connection.IOHandler.WriteLn(EncStr(AContext.Binding.PeerIP + ':' + IntToStr(AContext.Binding.Port) + 'M', EncDecStr, EncDecSIdx)); 
     TMyNotify.NotifyStr(@ManagerLoggedInNotify, AContext.Binding.PeerIP); 
    end 
    else if (UserName = GenUser) and (Password = GenPass) then 
    begin 
     Authenticating := False; 
     AContext.Connection.IOHandler.WriteLn(EncStr(AContext.Binding.PeerIP + ':' + IntToStr(AContext.Binding.Port) + 'U', EncDecStr, EncDecSIdx)); 
     TMyNotify.NotifyStr(@GeneralUserLoggedInNotify, AContext.Binding.PeerIP); 
    end else 
    begin 
     TIdNotify.NotifyMethod(@FailedAuthNotify); 
     AContext.Connection.Disconnect; 
    end; 
    Exit; 
    end; 

    //test for commands 
    if TextStartsWith(S, AssignID) then 
    begin 
    //command to assign a new unit id 

    Tmp := S; 
    Fetch(Tmp, '-'); 
    NewLoc := Fetch(Tmp, '-'); 
    NewUnit := Tmp; 

    if (NewLoc = '') or (NewUnit = '') then 
    begin 
     NewLoc := DefLocation; 
     NewUnit := DefUnitNum; 
    end; 

    AContext.Connection.IOHandler.WriteLn(PCommon.EncStr(Rebooting, EncDecStr, EncDecSIdx)); 

    TMyNotify.NotifyStr(@RebootNotify, S + #10 + NewLoc + #10 + NewUnit); 
    end; 
end; 

마지막으로, 당신은 메인 UI 스레드에서 모든 글로벌 변수 및 하트 비트/인증 타이머를 치우는 고려 건의 할 것입니다.대신 클라이언트의 ReadTimeout 속성 및/또는 CheckForDataOnSource() 메서드를 사용하여 OnExecute 이벤트 자체의 시간 초과 처리를 수행하십시오. TIdContext.Data 속성을 사용하거나 (TIdServerContext의 새 클래스를 가져와 TIdTCPServer.ContextClass 속성에 할당) 마지막으로 하트 비트를 받았거나 클라이언트가 여전히 인증 중인지 여부와 같은 연결 별 값을 추적합니다. 실제로 OnExecute이 실행되기 전에 OnConnect에서 인증을 처리하거나 클라이언트가 관리자로 로그인했는지 여부 등)로 인해 주 UI 스레드와 동기화해야하는 작업의 양이 줄어들고 동기화 처리 지연.

+0

감사합니다. 레미, 내일 첫 번째 구현하고 알려 드리겠습니다. – user7475089

+0

코드를 수정했습니다. 많은 것을 배웠지 만 통지를 위해 클래스를 사용하는 것에 익숙하지 않고 컴파일러에서 단어를 쓰는 방법을 모르므로 컴파일 할 때 각각 "오류 : 클래스 식별자가 필요합니다"라고 알려줍니다. 통고 절차. – user7475089

+0

@ user7475089 당신은'TFK20Elevator' 클래스가 있습니다. 유닛의 인터페이스에서 클래스의 선언에 추가 메소드를 추가 했습니까? –