Autor Beitrag
LokutusvB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 74

WinXP
Delphi 5, Delphi XE
BeitragVerfasst: Fr 23.02.18 12:58 
Hallo,

ich habe dieses Thema bereits im Delphi-PRAXiS-Forum eröffnet. Leider jedoch bekomme ich keine Antwort. Vielleicht kann mir hier jemand helfen.

Ich habe eine variable Anzahl von Servern im Netz, mit denen ich mich verbinden muß. Deren IP-Adressen werden in eine INI-Datei gespeichert (diese kann sich aber jederzeit ändern). Umsetzen möchte ich das Projekt in Delphi XE6 unter Verwendung der Indy-Komponenten.

Für das Verwalten der Verbindungsinformationen und der Indy-Clients habe ich mir ein Rord angelegt:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
tcpDataClients = record
 recIndex: Integer;
 tsC: TidTCPClient;
 tIp: String;
 ...
end;


Daraus erstelle ich in variables Array, lese die IP aus der INI-Datei und erzeuge die Indy-Clients, mit denen ich mich anschließend verbinde.

Die Informationen der Server erhalte ich bei ReadLn() der Indy-Komponenten. Hierfür habe ich mir eine Thread-Klasse erstellt. Um jeder erzeugten Instanz dieser Klasse eine Indy-Komponente zuordnen zu können, übergebe ich im Constructor eine Variable:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
Constructor TT_Lesen.Create;
begin
  Inherited Create(False);
  tcpRecIndex := Variable;
end;


Mit Hilfe einer For-Schleife kann ich nun die Thread-Instanzen erzeugen...

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TF_Main.Start;
var
  ii: Integer;
begin
  for ii := 0 to Length(tcpCls) - 1 do begin
    tcpCls[ii].recIndex := ii;
    tcpCls[ii].Lesen_Thread := TT_Lesen.Create(tcpCls[ii].recIndex);
    tcpCls[ii].Lesen_Thread.Priority := tpNormal;
    tcpCls[ii].Lesen_Thread.Resume();
  end;
end;


und die Indy-Clients können im Htread bei den Servern die Informationen einholen.

ausblenden Delphi-Quelltext
1:
txt := Trim(F_Main.tcpCls[tcpRecIndex].tsC.IOHandler.ReadLn());					


Das ganze funktioniert bei 2 bis 3 Clients sehr gut. Allerdings habe ich oft gehört, daß Delphi Threads Probleme bereiten sollen, inbesondere wenn man auf Variablen einer Form zugreift. Deswegen habe ich für jeden Indy-Client im Record die recIndex angelegt. Beispiele im Netz findet man leider sehr wenig, und wenn dann arbeiten die Leute mit Pointern.

Deswegen wollte ich wissen, ob meine Lösung "sauber" und ausfallsicher ist oder ob dabei zu Zugriffsfehlern auf den Record-Index kommen kann. Oder aber ob es vielleicht besser wäre, dem Thread direkt das Record-Objekt zu übergeben.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 23.02.18 13:42 
- Nachträglich durch die Entwickler-Ecke gelöscht -
LokutusvB Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 74

WinXP
Delphi 5, Delphi XE
BeitragVerfasst: Fr 02.03.18 12:12 
Moinsen,

die Lösung mit der Verwendung der Records klappt wunderbar, auch im "Dauerstresstest". Auch das Beenden des Programms (Threads terminieren, Verbindungen trennen...) klappt auf Programmebene wunderbar.

Ich habe das Programm als Windows-Dienst in Delphi neu erstellt, auch dieser funktioniert fehlerfrei bis auf das Stoppen des Dienstes. Auf Programmebene wartet das Terminate der Threads nicht, bis das Readln() der Indy-Komponenten ausgeführt wurde. Im Windows-Dienst wird der Dienst erst erfolgreich beendet, wenn jeder Thread, also jeder Indy-Client noch einmal ein ReadLn() durchgeführt hat. Wie kann ich das unterbinden und auch im Windows-Dienst die Threads beenden ohne das Warten auf ReadLn()?
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Sa 03.03.18 16:41 
Ich habe Indy nicht wirklich im Kopf, bzw. wegen der Warterei als unpraktisch abgehakt.
Aber gibt es nicht mitllerweile auch einen Aufruf der nur den aktuellen Puffer liefert und dessen laenge, ohne auf ein Zeilenende zu warten?
Also, generell solltest Du versuchen ohne Readline zu arbeiten und den Aufruf der nur Zeilenweise liefert selber implementieren. Schon ist das Problem weg.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
LokutusvB Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 74

WinXP
Delphi 5, Delphi XE
BeitragVerfasst: Di 06.03.18 11:05 
Das wäre ein Weg.

Ich habe mir mal die API und die Funktionen / Proceduren angeschaut, die der TidTCPClient zur Verfügung stellt. Und tatsächlich gibt es die Eigenschaft "ReadTimeOut". Zusammen mit ReadLn funktioniert auch nun das im Dienst wunderbar. :)

Trotzdem Danke dir für die Hilfe!