Einzelnen Beitrag anzeigen

romber

Registriert seit: 15. Apr 2004
Ort: Köln
1.164 Beiträge
 
Delphi 10 Seattle Professional
 
#1

Dauerhafte TCP-Verbindung: Access Violation???

  Alt 23. Mär 2009, 15:05
Hallo!

Ich habe mir einen kleinen TCP-Klienten erstellt, der die Verbindung mit dem Server aufbaut und dauerhaft verbunden bleibt. Dazu habe ich noch einen Thread erstellt, der die Verbindung überwacht und bei Bedarf wieder aufbaut. Zudem wird sichergestellt, dass immer nur einen Client-Thread existiert. Manche werden Fragen, wofür das ganze gut ist und behaupten, es ist nicht gut so usw. Das weiß ich auch selbst und bin auch einverstanden, dass es nicht die korrekteste Lösung ist! Aber die Sache wurde damals für einen ganz bestimmten Einsatz programmiert, hat jahrelang gut funktioniert und funktioniert jetzt auch noch, jedenfalls macht es seine Aufgabe.

Zum eigentlichen Problem ist es erst jetzt gekommen. Ein Update muss her, der Code wird neu kompiliert, und zwar mit Delphi 2009 und Indy10. Schnell wurde der Code für Indy10 angepasst. Es funktioniert sogar, aber nicht mehr ohne Probleme. Der Überwachungsthread meldet nach mehreren Versuchen, die abgebrochene Verbindung wieder aufzubauen, eine AV und bricht ab. Auch beim Schließen des Programms erscheint häufig eine Access Violation. Um sicher zu gehen, habe ich die andere Code entfernt und nur diese meine zwei Threads gelassen, somit ist es sicher, dass der Fehler von den Threads verursacht wird. Ich habe schon vieles versucht - ohne Erfolg. Brauche Eure Hilfe!!!

Weiter unten habe ich den Code des Formulars und der Threads gepostet:


Bitte bitte, sagt mir, wo das Problem liegt.

Delphi-Quellcode:
 //Formular, wo das Ganze aktiviert oder deaktiviert wird
unit FormMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TfrmMain = class(TForm)
    cbTCPConnection: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure cbTCPConnectionClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  frmMain: TfrmMain;
  ConnectionActive: Boolean;

implementation

uses
  Connection;

{$R *.dfm}

procedure TfrmMain.cbTCPConnectionClick(Sender: TObject);
begin
  ConnectionActive := cbTCPConnection.Checked;
  if cbTCPConnection.Checked = false then
  begin
    cbTCPConnection.Caption := 'nicht verbunden';
    if Assigned(TCPConnection) then
    TCPConnection.TCPClient.Disconnect;
  end
  else
  cbTCPConnection.Caption := 'Verbindung wird hergestellt...';
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if Assigned(TCPConnection) then
  TCPConnection.TCPClient.Disconnect;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  ConnectionActive := cbTCPConnection.Checked;
  TConnectionWatcher.Create(false);
end;

initialization
  TCPConnection := nil;

end.

//Und hier die beiden Threads

unit Connection;

interface

uses
  Classes, Dialogs, SysUtils, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

type
   TTCPConnectionClient = class(TThread)
   constructor Create (CreateSuspended: Boolean);
   destructor Destroy; override;
 private
   Status: string;
   RestData: string;
 protected
   procedure Execute; override;
   procedure ClientStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: String);
   procedure ChangeStatus;
 public
   TCPClient: TIdTCPClient;
   class function Use: TTCPConnectionClient;
end;

type
  TConnectionWatcher = class(TThread)
  constructor Create(CreateSuspended: Boolean);
  protected
    procedure Execute; override;
end;

var
  TCPConnection: TTCPConnectionClient;
  ConnectionCheckCounter: integer;

implementation

uses
  FormMain;

constructor TTCPConnectionClient.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FreeOnTerminate := true;
end;

destructor TTCPConnectionClient.Destroy;
begin
  if Assigned(TCPConnection) then
  TCPConnection := nil;
  inherited Destroy;
end;

procedure TTCPConnectionClient.ClientStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: String);
begin
   if AStatus = hsConnecting then
   Status := 'Verbindung wird hergestellt...'
   else if AStatus = hsConnected then
   Status := 'verbunden'
   else if (AStatus = hsDisconnecting) or (AStatus = hsDisconnected) then
   Status := 'nicht verbunden';
   Synchronize(ChangeStatus);
end;

procedure TTCPConnectionClient.ChangeStatus;
begin
  frmMain.cbTCPConnection.Caption := Status;
end;

procedure TTCPConnectionClient.Execute;
var
  RowData, Data, ServerData: string;
begin
  ConnectionCheckCounter := 0;
  TCPClient := TIdTCPClient.Create(nil);
  TCPClient.OnStatus := ClientStatus;
  TCPClient.Host := 'localhost';
  TCPClient.Port := 44491;

  try
    TCPClient.Connect;
    while not Terminated and TCPClient.Connected do
    begin
      ConnectionCheckCounter := 0;
      ServerData := TCPClient.IOHandler.ReadLn();
      if Length(ServerData) > 0 then
      begin
        //Hier kommt der Code für die Bearbeitung der empfangenen Daten. Dieser Code ist in Ordnung und ist nicht die Ursache des Problems.
      end;
    end;
  except
  end;

  if TCPClient.Connected then
  TCPClient.Disconnect;
  TCPClient.Free;
end;

class function TTCPConnectionClient.Use: TTCPConnectionClient;
begin
  if not Assigned(TCPConnection) then
  begin
    TCPConnection := TTCPConnectionClient.Create(false);
  end;
  Result := TCPConnection;
end;


constructor TConnectionWatcher.Create;
begin
  inherited Create(CreateSuspended);
  FreeOnTerminate := true;
end;

procedure TConnectionWatcher.Execute;
begin
  while not Terminated do
  begin
    if ConnectionActive then
    begin
      if TCPConnection = nil then
      TCPConnection := TTCPConnectionClient.Use
      else
      begin
        ConnectionCheckCounter := ConnectionCheckCounter + 1;
        if ConnectionCheckCounter = 5 then
        begin
          if TCPConnection <> nil then
          TCPConnection.TCPClient.Disconnect;
        end;
    end;
    end;
    Sleep(1000);
  end;
end;

end.
  Mit Zitat antworten Zitat