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!

War es hilfreich?

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

beschrieben

http: //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.)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top