Indy 10 IdTCPClient Lesen von Daten eines separaten Thread mit?
-
23-08-2019 - |
Frage
Frage: Was ich suche ist die typischsten oder best practice Art und Weise über einen separaten Thread zu verwenden, um Daten zu empfangen, einen IdTCPClient in Indy 10. mit
Hintergrund: Der Code unten ist ein Beispiel dessen, was ich versuche, den tatsächlichen Datenverarbeitungs Teile zur Klarheit entfernt zu tun. Die Idee des Gewindes ist, alle Daten (Variable Größe mit einem Kopf den Rest der Nachrichtenlänge erklärt) zu empfangen und dann zu analysieren (Das ist, was die HandleData Verfahren der Fall ist) und lösen einen Event-Handler auf dem Befehl abhängig.
Die TIdIOHandlerSocket wird durch die Hauptanwendung der Faden geführt, die auch Daten an die Buchse Schreibt wie und wann es erforderlich ist.
TScktReceiveThread = class(TThread)
private
{ Private declarations }
procedure HandleData;
protected
procedure Execute; override;
public
FSocket: TIdIOHandlerSocket;
constructor Create(CreateSuspended: boolean);
end;
procedure TScktReceiveThread.Execute;
var
FixedHeader: TBytes;
begin
Assert(FSocket <> nil, 'You must assign the connected socket to the receiving thread');
SetLength(FixedHeader, 2);
while not Terminated do
begin
if not FSocket.Connected then
Suspend
else
begin
FSocket.CheckForDataOnSource(10);
if not FSocket.InputBufferIsEmpty then
begin
FSocket.ReadBytes(FixedHeader, SizeOf(FixedHeader), false);
// Removed the rest of the reading and parsing code for clarity
Synchronize(HandleData);
end;
end;
end;
end;
Als Präfix habe ich eine andere Frage Stackoverflow verwendet, die mit den Serverkomponenten von Indy befasst: „ Delphi 2009, Indy 10, TIdTCPServer.OnExecute, wie all Bytes in dem Inputbuffer greifen", um die Basis was ich habe so weit.
Vielen Dank für jede Hilfe!
Lösung
Wenn Sie den Aufwand, indem Thread-Klassen für jeden einzelnen Client-Server-Datenaustausch auferlegt vermeiden wollen, können Sie eine frei bewegliche Threading Klasse erstellen, wie in
beschriebenhttp: //delphidicas.blogspot. com / 2008/08 / anonymous-Methoden-wenn-sollte-sie-be.html
Ich hatte das gleiche Problem vor ein paar Tagen und ich mir nur eine Klasse TMotileThreading schrieb die statischen Funktionen hat, die ich lassen Threads erstellen das neue anonyme Methode Merkmal D2009 verwenden. Sieht so etwas wie folgt aus:
type
TExecuteFunc = reference to procedure;
TMotileThreading = class
public
class procedure Execute (Func : TExecuteFunc);
class procedure ExecuteThenCall (Func : TExecuteFunc; ThenFunc : TExecuteFunc);
end;
Das zweite Verfahren ermöglicht es mir, eine Client-Server-Kommunikation durchzuführen, wie in Ihrem Fall und ein paar Sachen zu tun, wenn die Daten angekommen sind. Die nette Sache über anonyme Methoden ist, dass Sie die lokalen Variablen des anrufenden Kontext verwenden können. So eine Kommunikation sieht ungefähr wie folgt aus:
var
NewData : String;
begin
TMotileThreading.ExecuteThenCall (
procedure
begin
NewData := IdTCPClient.IOHandler.Readln;
end,
procedure
begin
GUIUpdate (NewData);
end);
end;
Die Execute und ExecuteThenCall Methode einfach einen Worker-Thread, setzt FreeOnTerminate auf true erstellen Speicherverwaltung zu vereinfachen und die bereitgestellten Funktionen in der Execute und OnTerminate Verfahren des Worker-Thread ausgeführt werden.
Ich hoffe, das hilft.
Bearbeiten (wie die vollständige Umsetzung der Klasse TMotileThreading angefordert)
type
TExecuteFunc = reference to procedure;
TMotileThreading = class
protected
constructor Create;
public
class procedure Execute (Func : TExecuteFunc);
class procedure ExecuteAndCall (Func : TExecuteFunc; OnTerminateFunc : TExecuteFunc;
SyncTerminateFunc : Boolean = False);
end;
TMotile = class (TThread)
private
ExecFunc : TExecuteFunc;
TerminateHandler : TExecuteFunc;
SyncTerminateHandler : Boolean;
public
constructor Create (Func : TExecuteFunc); overload;
constructor Create (Func : TExecuteFunc; OnTerminateFunc : TExecuteFunc;
SyncTerminateFunc : Boolean); overload;
procedure OnTerminateHandler (Sender : TObject);
procedure Execute; override;
end;
implementation
constructor TMotileThreading.Create;
begin
Assert (False, 'Class TMotileThreading shouldn''t be used as an instance');
end;
class procedure TMotileThreading.Execute (Func : TExecuteFunc);
begin
TMotile.Create (Func);
end;
class procedure TMotileThreading.ExecuteAndCall (Func : TExecuteFunc;
OnTerminateFunc : TExecuteFunc;
SyncTerminateFunc : Boolean = False);
begin
TMotile.Create (Func, OnTerminateFunc, SyncTerminateFunc);
end;
constructor TMotile.Create (Func : TExecuteFunc);
begin
inherited Create (True);
ExecFunc := Func;
TerminateHandler := nil;
FreeOnTerminate := True;
Resume;
end;
constructor TMotile.Create (Func : TExecuteFunc; OnTerminateFunc : TExecuteFunc;
SyncTerminateFunc : Boolean);
begin
inherited Create (True);
ExecFunc := Func;
TerminateHandler := OnTerminateFunc;
SyncTerminateHandler := SyncTerminateFunc;
OnTerminate := OnTerminateHandler;
FreeOnTerminate := True;
Resume;
end;
procedure TMotile.Execute;
begin
ExecFunc;
end;
procedure TMotile.OnTerminateHandler (Sender : TObject);
begin
if Assigned (TerminateHandler) then
if SyncTerminateHandler then
Synchronize (procedure
begin
TerminateHandler;
end)
else
TerminateHandler;
end;
Andere Tipps
Sie sind auf dem richtigen Weg. Indy ist bestimmt zu so verwendet werden. Es nutzt Steckdosen blockiert , so der ReadBytes
Anruf nicht zurück, bis er gelesen hat, was Sie gefragt haben. Vergleichen Sie das mit nicht-blockierende Sockets, wo ein Anruf früh zurückkehren kann, so dass Sie entweder Umfrage oder asynchron benachrichtigt, um zu bestimmen, wenn eine Anforderung gefüllt wurde.
Indy wird mit der Erwartung entwickelt, dass der Sockel Objekte ihre eigenen Fäden (oder Fasern). Indy kommt mit TIdAntifreeze
für die Leute, die ziehen möchten und Socket-Komponenten auf ihre Formulare und Datenmodule fallen und die Indy-Komponenten aus dem Haupt GUI-Thread verwenden, aber das ist nicht generell eine gute Idee, wenn Sie es vermeiden können.
Da der Thread nicht ohne FSocket
arbeiten kann zugewiesen werden, rate ich Ihnen einfach, um diesen Wert in den Konstruktor der Klasse zu erhalten. Behaupten im Konstruktor, wenn sie nicht zugewiesen wird. Darüber hinaus ist es ein Fehler Thread nicht aufgehängten zu schaffen, also warum sogar die Möglichkeit geben? (Wenn der Faden nicht ausgesetzt erstellt, dann wird es anfangen zu laufen, prüfen, ob FSocket
zugeordnet ist, und nicht, weil die Schaffung Thread nicht bekommen hat noch das Feld zuzuordnen.)