如何解决 Indy socket error #111 connection refused between Delphi 2007 server and RAD XE7 client?
How to solve Indy socket error #111 connection refused between Delphi 2007 server and RAD XE7 client?
当我单击服务器中的按钮时,调试器显示启动了两个线程,我假设一个是主线程,另一个是服务器线程,但 ServerExecute 过程从未执行,我认为导致连接被拒绝错误。
我该如何解决?
服务器代码:
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.
客户代码:
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.
编辑
我忘了说,客户应该在 android.
上 运行
这是错误的:
IdTCPServer1.Bindings.Add.IP := '0.0.0.0';
IdTCPServer1.Bindings.Add.Port := 2811;
您正在创建 两个 单独的绑定(这就是为什么您启动了两个线程)- 一个绑定到 0.0.0.0:0
,一个绑定到 0.0.0.0:2811
。
改成这样:
with IdTCPServer1.Bindings.Add do begin
IP := '0.0.0.0';
Port := 2811;
end;
或者这样:
IdTCPServer1.Bindings.Add.SetBinding('0.0.0.0', 2811, IdIP_v4);
或者直接将TIdTCPServer.DefaultPort
设置为2811,Bindings
不填写,激活后服务器会为你创建一个默认的0.0.0.0:2811
绑定项.
话虽如此,您的代码还有一些其他问题。
服务器:
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;
客户:
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
将它们改成更像这样的东西:
服务器:
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;
客户:
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;
当我单击服务器中的按钮时,调试器显示启动了两个线程,我假设一个是主线程,另一个是服务器线程,但 ServerExecute 过程从未执行,我认为导致连接被拒绝错误。
我该如何解决?
服务器代码:
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.
客户代码:
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.
编辑 我忘了说,客户应该在 android.
上 运行这是错误的:
IdTCPServer1.Bindings.Add.IP := '0.0.0.0';
IdTCPServer1.Bindings.Add.Port := 2811;
您正在创建 两个 单独的绑定(这就是为什么您启动了两个线程)- 一个绑定到 0.0.0.0:0
,一个绑定到 0.0.0.0:2811
。
改成这样:
with IdTCPServer1.Bindings.Add do begin
IP := '0.0.0.0';
Port := 2811;
end;
或者这样:
IdTCPServer1.Bindings.Add.SetBinding('0.0.0.0', 2811, IdIP_v4);
或者直接将TIdTCPServer.DefaultPort
设置为2811,Bindings
不填写,激活后服务器会为你创建一个默认的0.0.0.0:2811
绑定项.
话虽如此,您的代码还有一些其他问题。
服务器:
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;
客户:
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
将它们改成更像这样的东西:
服务器:
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;
客户:
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;