I have created two TIdTCPClient objects and connected them to the same server.
The server receives bytes from one client and sends them to the other. This client sends it to the first client and so on in a circle.
The problem is that it doesn't work after I push the button while the timer is disabled. But if I activate the timer, it works with the timer's frequency.
type
TForm2 = class(TForm)
Client1: TIdTCPClient;
Client2: TIdTCPClient;
Timer1: TTimer;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
idThreadComponent : TIdThreadComponent;
procedure IdThreadComponentRun(Sender: TIdThreadComponent);
procedure IdTCPClientConnected(Sender: TObject);
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
idThreadComponent:= TIdThreadComponent.Create();
idThreadComponent.OnRun := IdThreadComponentRun;
Client1.Port:= 1202;
Client1.Host:= 'localhost';
Client2.Port:= 1203;
Client2.Host:= 'localhost';
Client1.OnConnected:= IdTCPClientConnected;
Client2.OnConnected:= IdTCPClientConnected;
Client1.Connect;
Client2.Connect;
end;
procedure TForm2.IdThreadComponentRun(Sender: TIdThreadComponent);
var
Rx: TIDBytes;
begin
if not Client1.IOHandler.InputBufferIsEmpty then
begin
Client1.IOHandler.ReadBytes(Rx, Client1.IOHandler.InputBuffer.Size);
if Length(Rx) > 0 then
begin
Client2.IOHandler.Write(Rx);
end
end;
if not Client2.IOHandler.InputBufferIsEmpty then
begin
Client2.IOHandler.ReadBytes(Rx, Client2.IOHandler.InputBuffer.Size);
if Length(Rx) > 0 then
begin
Client1.IOHandler.Write(Rx);
end;
end;
end;
procedure TForm2.IdTCPClientConnected(Sender: TObject);
begin
IdThreadComponent.Active := True;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
Tx: TIDBytes;
begin
SetLength(Tx, 1);
Client1.IOHandler.Write(Tx,length(Tx));
end;
procedure TForm2.Timer1Timer(Sender: TObject);
begin
if not Client1.Connected then
begin
end;
if not Client2.Connected then
begin
end;
end;
The problem is that the only place you are actually reading incoming data into the two InputBuffer
s is in the timer event. Without the two calls to Connected()
(which perform reads internally), the InputBuffer
s will always be empty, so there is no work for the thread to do.
Get rid of the timer, and have the thread use CheckForDataOnSource()
instead, eg:
procedure TForm2.IdThreadComponentRun(Sender: TIdThreadComponent);
var
Rx: TIdBytes;
begin
Client1.IOHandler.CheckForDataOnDource(0);
Client1.IOHandler.CheckForDisconnect;
if not Client1.IOHandler.InputBufferIsEmpty then
begin
Client1.IOHandler.ReadBytes(Rx, -1);
Client2.IOHandler.Write(Rx);
Rx := nil;
end;
Client2.IOHandler.CheckForDataOnSource(0);
Client2.IOHandler.CheckForDisconnect;
if not Client2.IOHandler.InputBufferIsEmpty then
begin
Client2.IOHandler.ReadBytes(Rx, -1);
Client1.IOHandler.Write(Rx);
Rx := nil;
end;
end;
Alternatively, just use 2 separate reading threads and let ReadBytes() block normally, eg:
procedure TForm2.IdThreadComponent1Run(Sender: TIdThreadComponent);
var
Rx: TIdBytes;
begin
Client1.IOHandler.ReadBytes(Rx, -1);
Client2.IOHandler.Write(Rx);
end;
procedure TForm2.IdThreadComponent2Run(Sender: TIdThreadComponent);
var
Rx: TIdBytes;
begin
Client2.IOHandler.ReadBytes(Rx, -1);
Client1.IOHandler.Write(Rx);
end;