문제

의문: 내가 찾고있는 것은 가장 전형적인 또는 모범 사례 별도의 스레드를 사용하여 Indy 10의 IDTCPClient를 사용하여 데이터를 수신하는 방법.

배경: 아래 코드는 명확성을 위해 제거 된 실제 데이터 처리 부품과 함께하려는 내용의 샘플입니다. 스레드의 아이디어는 모든 데이터 (나머지 메시지 길이를 선언하는 헤더가있는 가변 크기)를 수신 한 다음 구문 분석하고 (handledata 절차가하는 일) 명령에 따라 이벤트 핸들러를 트리거하는 것입니다.

TidioAndlersocket은 주 응용 프로그램에 의해 스레드로 전달되며, 필요 시점과 소켓에 데이터를 작성합니다.

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;

접두사로서, 나는 Indy의 서버 구성 요소를 다루는 또 다른 stackoverflow 질문을 사용했습니다. "Delphi 2009, Indy 10, Tidtcpserver.onexecute, 입력 부퍼의 모든 바이트를 잡는 방법"지금까지 내가 가진 것의 기초를 얻기 위해.

도움을 주셔서 감사합니다!

도움이 되었습니까?

해결책

각 클라이언트 서버 데이터 교환에 대한 스레드 클래스를 생성하여 오버 헤드를 피하려면 다음에 설명 된대로 모터 스레딩 클래스를 만들 수 있습니다.

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

나는 며칠 전에 같은 문제를 겪었고 방금 D2009의 새로운 익명 메소드 기능을 사용하여 스레드를 생성 할 수있는 정적 기능을 갖는 클래스 tmotileThreading을 저에게 썼습니다. 다음과 같이 보입니다.

type
  TExecuteFunc = reference to procedure;

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

두 번째 절차를 통해 귀하의 경우와 같이 클라이언트 서버 커뮤니케이션을 수행하고 데이터가 도착할 때마다 몇 가지 작업을 수행 할 수 있습니다. 익명의 방법에 대한 좋은 점은 호출 컨텍스트의 로컬 변수를 사용할 수 있다는 것입니다. 따라서 커뮤니케이션은 다음과 같이 보입니다.

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

Execute and ExecuteThenCall 메소드는 단순히 작업자 스레드를 생성하고 FreeOnterminate를 TRUE로 설정하여 메모리 관리를 단순화하고 작업자 스레드의 실행 및 onterminate 프로 시저에서 제공된 기능을 실행합니다.

도움이되기를 바랍니다.

편집하다 (클래스 tmotileThreading의 전체 구현을 요청한대로)

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;

다른 팁

당신은 올바른 길을 가고 있습니다. 인디입니다 예정된 그렇게 사용됩니다. 사용합니다 차단 소켓, 그래서 ReadBytes 요청한 내용을 읽을 때까지 전화는 반환되지 않습니다. 전화가 일찍 돌아올 수있는 비 블로킹 소켓과 대조하므로 요청이 채워진시기를 결정하기 위해 신중하게 통지하거나 통지를받습니다.

Indy는 소켓 객체에 자체 스레드 (또는 섬유)가있을 것으로 예상하여 설계되었습니다. 인디가 함께 온다 TIdAntifreeze 소켓 구성 요소를 양식 및 데이터 모듈로 드래그 앤 드롭하여 주 GUI 스레드에서 Indy 구성 요소를 사용하려는 사람들의 경우,이를 피할 수있는 경우 일반적으로 좋은 생각은 아닙니다.

당신의 스레드는 없이는 작동 할 수 없기 때문입니다 FSocket 할당되면 클래스의 생성자에서 그 값을 간단히받는 것이 좋습니다. 할당되지 않은 경우 생성자를 제작하십시오. 또한, 그것은입니다 오류 스레드를 사용하지 않으려면 왜 옵션을 제공합니까? (스레드가 일시 중단되지 않으면 실행이 시작됩니다. FSocket 생성 스레드가 아직 해당 필드를 할당하지 않았기 때문에 할당되고 실패합니다.)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top