android - 如何解决 Delphi 2007 服务器和 RAD XE7 客户端之间的 Indy 套接字错误 #111 连接被拒绝?

标签 android delphi indy delphi-2007 delphi-xe7

当我单击服务器中的按钮时,调试器显示启动了两个线程,我假设一个是主线程,另一个是服务器线程,但 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;

您正在创建两个单独的绑定(bind)(这就是启动两个线程的原因) - 一个绑定(bind)到 0.0.0.0:0,另一个绑定(bind)到 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,那么服务器将创建一个绑定(bind)到 的默认项激活后为您提供 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;

关于android - 如何解决 Delphi 2007 服务器和 RAD XE7 客户端之间的 Indy 套接字错误 #111 连接被拒绝?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28901633/

相关文章:

delphi - TIdHTTPServer 在我的 DUnit 测试中激活它时引发 EThread 错误 6

delphi - 在 Windows 8 上的 Delphi XE 中使用 Indy 时 Gmail 失败,错误代码为 'Connection Closed Gracefully'

java - 错误地覆盖包

sql-server - 当它是强制参数时,如何在不显式写入数据库名称的情况下编写通用脚本

delphi 文本矩形 自动换行

delphi - 改善旧系统(尤其是笔记本电脑(Delphi 6))上的Indy HTTP客户端性能?

java - 使用 String 参数调用时 JNI 崩溃

android - 如何禁用回收器 View 滚动以便它监听 Scrollview 布局?

android - 带有 actionbarsherlock 的昏暗、几乎透明的 Activity

ios - 创建 iOS 应用程序的工作流程是什么