별도의 스레드를 사용한 데이터를 읽는 Indy 10 idtcpclient?
-
23-08-2019 - |
문제
의문: 내가 찾고있는 것은 가장 전형적인 또는 모범 사례 별도의 스레드를 사용하여 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
생성 스레드가 아직 해당 필드를 할당하지 않았기 때문에 할당되고 실패합니다.)