问题
A TCP server is sending data frames continuosly every 8ms. I want to program a client able to receive these data frames. Is there any procedure in Indy 9 to know if there is data available in the buffer?
My current programs is the following (I am using a Thread):
procedure TThreadRead.Execute;
var
buffer: array [0..755] of byte;
//s1: string;
//i: integer;
begin
IdTCPClient1.RecvBufferSize:= 756;
IdTCPClient1.Connect;
while Terminated = false do
begin
if IdTCPClient1.InputBuffer.Size = 0 then
IdTCPClient1.ReadFromStack(True,0,False);
while IdTCPClient1.InputBuffer.Size > 0 do
begin
ReadBuffer(buffer, FClient.InputBuffer.Size);
//s1:= '';
//For i:=0 To Length(buffer)-1 Do
// s1:=s1+IntToHex(Ord(buffer[i]),2); //Read values-->global var
//Form1.Memo1.Text:=s1;
end;
end;
end;
Is there any more efficient solution for reading TCP data continuously (like onread event in UDP)?
Thanks in advance.
回答1:
TIdTCPClient
is not an asynchronous component. It does not tell you when data arrives. You need to use a Timer or a Thread to periodically poll the socket for new data (TIdUDPServer
uses an internal thread to trigger its OnUDPRead
event), eg:
procedure TForm1.Button1Click(Sender: TObject);
begin
IdTCPClient1.Connect;
Timer1.Enabled := True;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Timer1.Enabled := False;
IdTCPClient1.Disconnect;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
s1: string;
begin
s1 := IdTCPClient1.CurrentReadBuffer;
...
end;
With that said, CurrentReadBuffer()
is generally not the best choice to use. Typically you would do something more like this instead:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
IdTCPClient1.ReadFromStack(True, 0, False);
while IdTCPClient1.InputBuffer.Size > 0 do
begin
// read one complete frame and process as needed ...
end;
Timer1.Enabled := True;
end;
Update: given new information about the frame structure and your switch to a thread, you should be doing this instead:
procedure TThreadRead.Execute;
var
buffer: array of Byte;
numbytes: Integer;
begin
SetLength(buffer, 0);
IdTCPClient1.Connect;
try
while not Terminated do
begin
numbytes := StrToInt('$' + IdTCPClient1.ReadString(8)) - 8;
if numbytes <> Length(buffer) then
SetLength(buffer, numbytes);
if numbytes > 0 then
IdTCPClient1.ReadBuffer(buffer[0], numbytes);
// process buffer up to numbytes as needed...
end;
finally
IdTCPClient1.Disconnect;
end;
end;
来源:https://stackoverflow.com/questions/10881685/indy-tcp-read-data-in-a-loop