Reputation: 2428
When I click on the button in the server the debugger shows two threads are started, I'm assuming one is the main thread and the other one is the server's thread, but the ServerExecute procedure is never executed, which I think causes the connection refused error.
How can I fix it?
Server code:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, IdContext,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
IdTCPServer1: TIdTCPServer;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure ExecuteServer(AContext : TIdContext);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
IdTCPServer1.Bindings.Add.IP := '0.0.0.0';
IdTCPServer1.Bindings.Add.Port := 2811;
IdTCPServer1.OnExecute := ExecuteServer;
IdTCPServer1.Active := True;
end;
procedure TForm1.ExecuteServer(AContext: TIdContext);
begin
Sleep(Random(3000));
Memo1.Lines.Add('Hello World');
AContext.Connection.IOHandler.WriteLn('Hello World');
end;
end.
Client code:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, FMX.Layouts,
FMX.Memo, FMX.StdCtrls, IdGlobal, IdIntercept;
type
TpocForm1 = class(TForm)
ButtonConnect: TButton;
ButtonDisconnect: TButton;
Memo1: TMemo;
procedure ButtonConnectClick(Sender: TObject);
procedure ButtonDisconnectClick(Sender: TObject);
procedure AddLine(text : String);
private
public
{ Public declarations }
end;
TpocTCPClientThread = class(TThread)
TCPClient: TIdTCPClient;
protected
procedure Execute; override;
procedure AddLineToMemo;
procedure Connect;
procedure Disconnect;
end;
var
pocForm1: TpocForm1;
implementation
{$R *.fmx}
Const
PC_IP = '192.168.32.252';
PORT = 2811;
var
thread: TpocTCPClientThread;
procedure TpocForm1.ButtonConnectClick(Sender: TObject);
begin
Memo1.Lines.Add('Client connected with server');
thread:= TpocTCPClientThread.Create(False);
end;
procedure TpocForm1.ButtonDisconnectClick(Sender: TObject);
begin
thread.Terminate;
thread.WaitFor;
FreeAndNil(thread);
Memo1.Lines.Add('Client disconnected from server');
end;
procedure TpocForm1.AddLine(text : String);
begin
Memo1.Lines.Add(text);
end;
procedure TpocTCPClientThread.Execute();
begin
Connect;
while not Terminated do
begin
Synchronize(AddLineToMemo);
end;
Disconnect;
end;
procedure TpocTCPClientThread.AddLineToMemo;
begin
pocForm1.AddLine(TCPClient.IOHandler.ReadLn(IndyTextEncoding_OSDefault()));
end;
procedure TpocTCPClientThread.Connect;
begin
TCPClient := TIdTCPClient.Create;
TCPClient.Host := PC_IP;
TCPClient.Port := PORT;
TCPClient.Connect;
end;
procedure TpocTCPClientThread.Disconnect;
begin
TCPClient.Disconnect;
TCPClient.Free;
end;
end.
edit I forgot to mention, the client is supposed to run on android.
Upvotes: 2
Views: 3342
Reputation: 595320
This is wrong:
IdTCPServer1.Bindings.Add.IP := '0.0.0.0';
IdTCPServer1.Bindings.Add.Port := 2811;
You are creating two separate bindings (which is why you get two threads started) - one bound to 0.0.0.0:0
and one bound to 0.0.0.0:2811
.
Change it to this:
with IdTCPServer1.Bindings.Add do begin
IP := '0.0.0.0';
Port := 2811;
end;
Or this:
IdTCPServer1.Bindings.Add.SetBinding('0.0.0.0', 2811, IdIP_v4);
Or, simply set the TIdTCPServer.DefaultPort
to 2811 and do not fill in the Bindings
at all, then the server will create a default item bound to 0.0.0.0:2811
for you when activated.
With that said, there are some other problems with your code.
Server:
procedure TForm1.ExecuteServer(AContext: TIdContext);
begin
Sleep(Random(3000));
Memo1.Lines.Add('Hello World'); // <- must be synchronized!
AContext.Connection.IOHandler.WriteLn('Hello World'); // <- default ASCII encoding used
end;
Client:
procedure TpocTCPClientThread.Execute();
begin
Connect;
while not Terminated do
begin
Synchronize(AddLineToMemo); // <- calling ReadLn() inside of Synchronize()
end;
Disconnect; // <- not called if an exception is raised
end;
TCPClient.IOHandler.ReadLn(IndyTextEncoding_OSDefault()) // <- OSDefault is not consistent across platforms
Change them to something more like this instead:
Server:
procedure TForm1.Button1Click(Sender: TObject);
begin
...
IdTCPServer1.OnConnect := ConnectServer;
...
end;
procedure TForm1.ConnectServer(AContext: TIdContext);
begin
AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8();
end;
procedure TForm1.ExecuteServer(AContext: TIdContext);
begin
Sleep(Random(3000));
TThread.Synchronize(nil,
procedure
begin
Memo1.Lines.Add('Hello World');
end
);
AContext.Connection.IOHandler.WriteLn('Hello World');
end;
Client:
procedure TpocForm1.ButtonConnectClick(Sender: TObject);
begin
thread := TpocTCPClientThread.Create(False);
end;
procedure TpocForm1.ButtonDisconnectClick(Sender: TObject);
begin
thread.Terminate;
thread.WaitFor;
FreeAndNil(thread);
end;
procedure TpocTCPClientThread.Execute();
begin
Connect;
try
AddLineToMemo('Client connected with server');
TCPClient.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8();
while not Terminated do
begin
AddLineToMemo(TCPClient.IOHandler.ReadLn());
end;
finally
Disconnect;
AddLineToMemo('Client disconnected from server');
end;
end;
procedure TpocTCPClientThread.AddLineToMemo(text: string);
begin
Synchronize(
procedure
begin
pocForm1.AddLine(text);
end
);
end;
Upvotes: 3