2009-02-16 13 views
5

Soru: Aşağıdaki kod bir geçerli: Ne aradığım en tipik veya en iyi uygulama 10.Indy 10 IdTCPClient Ayrı bir iş parçacığı kullanarak veri okuma?

Arkaplan Indy bir IdTCPClient kullanarak veri almak için ayrı bir iş parçacığı kullanmak yoludur netlik için kaldırılan gerçek veri işleme parçaları ile ne yapmaya çalıştığımı örnek. İş Parçasının Fikri, tüm verileri (mesaj uzunluğunun geri kalanını bildiren bir başlık ile değişken boyut) almak ve daha sonra (HandleData prosedürünün yaptığı şey) ayrıştırmak ve komutuna bağlı olarak bir Olay İşleyicisini tetiklemektir.

TIdIOHandlerSocket, ana uygulama tarafından iş parçacığına geçirilir ve bu da veriyi gerektiği gibi sokete yazar.

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; 

bir önek olarak Indy sunucu bileşenleri ile ilgilenen başka bir StackOverflow soru kullanmış: "Delphi 2009, Indy 10, TIdTCPServer.OnExecute, how to grab all the bytes in the InputBuffer" Ben bugüne kadar ne temelini olsun.

Yardımlarınız için teşekkürler!

cevap

8

Yüklemeden kaçınmak istiyorsanız

http://delphidicas.blogspot.com/2008/08/anonymous-methods-when-should-they-be.html

açıklandığı gibi her biri için iplik sınıfları ve her istemci-sunucu veri alışverişi oluşturarak daha bir kaç gün önce aynı sorunu vardı ve ben sadece bana bir sınıf TMotileThreading yazdığı hareketli bir iş parçacığı sınıf oluşturabilir D2009'un yeni anonim yöntem özelliğini kullanarak konuları oluşturmama izin veren statik işlevlere sahip.

type 
    TExecuteFunc = reference to procedure; 

    TMotileThreading = class 
    public 
    class procedure Execute (Func : TExecuteFunc); 
    class procedure ExecuteThenCall (Func : TExecuteFunc; ThenFunc : TExecuteFunc); 
    end; 

ikinci prosedür bana durumda bir istemci-sunucu iletişimi gibi gerçekleştirmek ve veri geldi zaman bazı şeyler yapmanızı sağlar: Böyle bir şey görünüyor. Anonim yöntemlerle ilgili güzel şey, çağrı içeriğinin yerel değişkenlerini kullanabilmenizdir.Yani bir iletişim şöyle görünür:

var 
    NewData : String; 
begin 
    TMotileThreading.ExecuteThenCall (
    procedure 
    begin 
     NewData := IdTCPClient.IOHandler.Readln; 
    end, 
    procedure 
    begin 
     GUIUpdate (NewData); 
    end); 
end; 

Çalıştırma ve ExecuteThenCall yöntemi sadece bir çalışan iş parçacığı oluşturmak, bellek yönetimi basitleştirmek ve iş parçacığının çalıştırma ve OnTerminate prosedürler sağlanan işlevleri yürütmek için true FreeOnTerminate ayarlayın.

Bu yardımcı olur umarım.

DÜZENLEME

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; 
+0

Bu çok zarif, ancak tüm uygulamayı istediğiniz yere gönderdiniz mi? Gönderinizde TMotileThreading sınıfının tam kullanımını bulamadım. – jamiei

+0

Uygulamamı cevaba ekledim. – jpfollenius

+0

Teşekkür ederim Smasher - Orijinal olarak yayınlandığında bunu neden kabul etmediğimi hatırlayamıyorum ama şimdi kabul edildi. ;) – jamiei

5

Doğru yoldasınız. Indy , kullanım amaçlıdır. Bu, bloklama soketlerini kullanır, böylece ReadBytes aramanız, istediğiniz şeyi okuyana kadar geri dönmez. Bir çağrının erkenden geri gelebileceği engelleme olmayan soketlerle kontrast sağlayın, böylece bir isteğin ne zaman dolduğunu belirlemek için ya yoksayın veya eşzamansız olarak bildirim alırsınız. Indy, soket nesnelerine ait ipliklerin (veya fiberlerin) olması beklentisi ile tasarlanmıştır. Indy, soket bileşenlerini form ve veri modüllerine sürükleyip bırakmak isteyen kişiler için TIdAntifreeze ile birlikte gelir ve Indy bileşenlerini ana GUI iş parçacığından kullanır, ancak bunu önlemek için genellikle iyi bir fikir değildir.

Iş parçacığınız, atanan FSocket olmadan çalışamadığından, sınıfın yapıcısında bu değeri almanızı öneriyorum. Atanmamışsa kurucuda onaylayın. Ayrıca, iş parçacığınızı askıya alınamayan bir hatasıdır, bu nedenle neden seçenek bile verilsin? (Eğer iş parçacığı askıya alınmadıysa, o zaman çalışmaya başlar, FSocket öğesinin atanıp atanmadığını kontrol eder ve başarısız olursa, oluşturma iş parçacığı henüz bu alanı atamak için başarısız olur.)

+0

Ah evet, sen CreateSuspended hakkında kesinlikle haklısınız (sınıf TMotileThreading tam olarak uygulanmasını talep gibi). Yapıştırmayla ilgili bir hata, bir kurucuyu varsayılan bir iş parçacığından kopyaladım çünkü orijinalim kodu gereksiz yere karmaşık hale getireceğimi düşündüğüm başka bir şeyden geçiyor! Özür dilerim! – jamiei

İlgili konular