Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Dauerhafte TCP-Verbindung: Access Violation??? (https://www.delphipraxis.net/131337-dauerhafte-tcp-verbindung-access-violation.html)

romber 23. Mär 2009 15:05


Dauerhafte TCP-Verbindung: Access Violation???
 
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.

Assertor 23. Mär 2009 19:28

Re: Dauerhafte TCP-Verbindung: Access Violation???
 
Hi romber,

Zitat:

Zitat von romber
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.

Zitat:

Zitat von romber
Delphi-Quellcode:
procedure TConnectionWatcher.Execute;
begin
  while not Terminated do
  begin
    if frmMain.cbTCPConnection.Checked then // das dürfte Probleme verursachen
    begin
      ...
    end;
  end;
end;

Ad hoc fällt mir nur der unsychronisierte Zugriff auf das VCL Element (s.o.) auf - das ist immer wieder gerne ein Grund für AVs.

Kannst Du den Fehler nicht weiter eingrenzen? Springt der Debugger denn nicht rein?

Gruß Assertor

romber 23. Mär 2009 20:33

Re: Dauerhafte TCP-Verbindung: Access Violation???
 
Hi Assertor!

Danke für die Antwort!
Tatsächlich konnte das Problem bei unsinchronisiertem Zugriff liegen. Komisch ist, dass es damals mit Indy9 und Delphi7 dieses Problem nicht da war.
Ich versuche, den Fehler weiter einzugrenzen und melde mich wieder. Danke!

Assertor 23. Mär 2009 21:00

Re: Dauerhafte TCP-Verbindung: Access Violation???
 
Hi,

Zitat:

Zitat von romber
Danke für die Antwort!

Keine Ursache :)

Zitat:

Zitat von romber
Tatsächlich konnte das Problem bei unsinchronisiertem Zugriff liegen. Komisch ist, dass es damals mit Indy9 und Delphi7 dieses Problem nicht da war.
Ich versuche, den Fehler weiter einzugrenzen und melde mich wieder. Danke!

Ja, vielleicht ist es wirklich nur eine kleine Ursache mit großer Wirkung. Das es bisher keine Probleme gab würde ich eher unter "Glück" einordnen - eine Mögliche Ursache ist es ja auf jeden Fall. Sag einfach bescheid hier.

Gruß Assertor

romber 24. Mär 2009 09:52

Re: Dauerhafte TCP-Verbindung: Access Violation???
 
Ich habe eine globale Variable "ConnectionActive" erstellt und prüfe diese, anstatt direkt auf das CheckBox zuzugreifen.
Fas Problem besteht leider nach wie vor.

Assertor 24. Mär 2009 10:43

Re: Dauerhafte TCP-Verbindung: Access Violation???
 
Hi romber,

kannst Du bitte ein Demoprojekt machen (also Units und Forms) und als Zip hier im Thread posten?

Gruß Assertor

romber 24. Mär 2009 11:30

Re: Dauerhafte TCP-Verbindung: Access Violation???
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe das Demo-Projekt angehängt. Die Routine zum Bearbeiten der empfangenen Daten sieht in meinem Projekt etwas anders aus als im Demo Projekt, der Server und Client kommunizieren nach einem bestimmten Protokol, aber an dieser Routine liegt der Fehler nicht. Ich muss auch noch sagen, das AV nicht immer auftaucht. Man sollte sich nicht wundern, wenn man das Projekt ausführt und alles glatt läuft. Es taucht plötzlich auf, manchmal nach mehreren Versuchen.

Das Problem taucht auf
- beim Schließen des Programms und
- beim Versuch des Überwachungsthreads, die abgebrochene Verbindung wieder herzustellen. Dabei wird der Überwachungsthread, der eigentlich immer laufen muss, beendet.

Assertor 26. Mär 2009 08:30

Re: Dauerhafte TCP-Verbindung: Access Violation???
 
Hi romber,

ich habe Deine Demoprojekt bisher etliche Male durchlaufen lassen - aber bei keiner Konstellation have ich eine AV bekommen... Ich würde jetzt vorschlagen, daß Du die kostenfreie Version von madExcept mal in Deinem Projekt verwendest, damit Du wenn der Fehler auftritt einen genauen Bugreport bekommst. Das ist für die Suche viel einfacher. Diesen Bug Report kannst Du mir dann gerne mailen bzw. hier posten.

Leider kann ich da wohl im Moment nicht besser helfen...

Gruß Assertor

romber 26. Mär 2009 14:58

Re: Dauerhafte TCP-Verbindung: Access Violation???
 
Danke, Assertor!

Ich versuche es mit madExcept und melde mich wieder!


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:12 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz