Einzelnen Beitrag anzeigen

A.Griffin

Registriert seit: 17. Feb 2017
94 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

Indy TCPClient Lesethread sicher beenden

  Alt 10. Nov 2017, 14:28
Hallo zusammen,

ich habe versucht den Lesethread von hier umzusetzen.

Code:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent, idsync,
  IdTCPConnection, IdTCPClient, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    MemoReceive: TMemo;
    Button1: TButton;
    Client: TIdTCPClient;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ClientConnected(Sender: TObject);
    procedure ClientDisconnected(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TReadingThread = class(TThread)
  protected
    FConn: TIdTCPConnection;
    procedure Execute; override;
    procedure DoTerminate; override;
  public
    constructor Create(AConn: TIdTCPConnection); reintroduce;
  end;

  TLog = class(TidSync)
  protected
    FMsg: String;
    procedure DoSynchronize; override;
  public
    constructor Create(const AMsg: String);
    class procedure AddMsg(const AMsg: String);
  end;

var
  Form1: TForm1;
  rt: TReadingThread = nil;

implementation

var
  oldStatusReceive: string = 'Disconnected';
  oldStatusSend: string = 'Disconnected';
  TelegramNr: string = '00';
  sendCounter: Integer = 1;
  CommissionNumber: Integer = 1;

{$R *.dfm}

constructor TReadingThread.Create(AConn: TIdTCPConnection);
begin
  TLog.AddMsg('DEBUG: TReadingThread.Create');
  FConn := AConn;
  inherited Create(False);
end;

procedure TReadingThread.Execute;
var
  cmd, tcpStringSend: string;
begin
  TLog.AddMsg('DEBUG: TReadingThread.Execute');

  while not Terminated do
  begin
    cmd := FConn.IOHandler.ReadLn(#3);
    cmd := trim(cmd);
    TLog.AddMsg('DEBUG: TReadingThread.Execute. Cmd: ' + cmd);
    TelegramNr := copy(cmd, 1, 2);
    tcpStringSend := #2 + TelegramNr + '001050QU' + #3;
    FConn.IOHandler.WriteLn(tcpStringSend);
  end;
end;

procedure TReadingThread.DoTerminate;
begin
  TLog.AddMsg('DEBUG: TReadingThread.DoTerminate');
  inherited;
end;

constructor TLog.Create(const AMsg: string);
begin
  inherited Create;
  FMsg := AMsg;
end;

procedure TLog.DoSynchronize;
begin
  Form1.MemoReceive.Lines.Add(FMsg);
end;

class procedure TLog.AddMsg(const AMsg: string);
begin
  with Create(AMsg) do
    try
      Synchronize;
    finally
      Free;
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Host: string;
  Port: Integer;
begin
  Host := '192.168.100.74';
  Port := StrToInt('4100');

  Client.Host := Host;
  Client.Port := Port;

  try
    Client.Connect;
  except
    on E: Exception do
      TLog.AddMsg('Error: ' + E.Message);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  try
    Client.Disconnect;
  except
    on E: Exception do
      TLog.AddMsg('Error: ' + E.Message);
  end;
end;

procedure TForm1.ClientConnected(Sender: TObject);
begin
  TLog.AddMsg('DEBUG: TForm1.clientConnected');
  rt := TReadingThread.Create(Client);
end;

procedure TForm1.ClientDisconnected(Sender: TObject);
begin
  TLog.AddMsg('DEBUG: TForm1.clientDisconnected');
  if rt <> nil then
  begin
    rt.Terminate;
    rt.WaitFor;
    FreeAndNil(rt);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MemoReceive.Clear;
end;

end.
Wie lässt sich die Verbindung sicher beenden? Ich habe einen Disconnect Button hinzugefügt, aber wenn ich da drauf klicke bekomme ich eine Exception (Project1.exe raised exception class EIdNotConnected with message 'Not Connected'.) Ich nehme an, dass passiert, weil der Lesethread noch läuft und dann plötzlich die Verbindung weg ist. Wenn ich die Anwendung nach dem Verbinden einfach schließe passiert das gleiche. Ich muss also erst den Lesethread beenden und dann die Verbindung kappen. Wie beende ich den Thread, wenn er gerade beim "ReadLn" hängt und vom Server da nichts kommt? Ich habe versucht das Terminate, WaitFor, FreeAndNil vom Disconnected Event vor dem Disconnect zu machen aber dann friert die Anwendung einfach ein. Hat einer eine Idee?
  Mit Zitat antworten Zitat