【问题标题】:Indy 10 TCPServer does not communicate with connected clients on LinuxIndy 10 TCPServer 不与 Linux 上连接的客户端通信
【发布时间】:2011-10-14 12:31:36
【问题描述】:

我遇到了一个问题,让我陷入困境。我正在尝试将 Windows 上的 Indy 10 客户端/服务器应用程序的服务器端移植到 Linux 以节省成本。该应用程序最初是使用 Delphi 2010 开发的。我已经将它移植到 Lazarus/FreePascal 并且它在 Windows 上运行良好。鉴于 Lazarus/FreePascal 是多平台且免费的,因此它是该工作的理想人选。

我已尽我所能让服务器应用程序在 Linux 上运行,但没有成功。服务器只是不与连接的客户端通信。什么都没有!

然后我决定回到第一方。我试图获得一个在 Linux 上工作的非常基本的示例。相关部分源码如下图

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  s: string;
  i: Integer;
begin
  with AContext.Connection.IOHandler do
  try
    WriteLn('Type an integer and Enter');
    s := ReadLn;
    try
      i := StrToInt(s);
      WriteLn(s + ' squared is ' + IntToStr(i*i));
    except
      WriteLn(s + ' is not an integer');
    end;
  finally
    Free;
  end;
end;

procedure TForm1.FormActivate(Sender: TObject);
var
  Binding: TIdSocketHandle;
begin
  {$IFDEF UNIX}
  Binding := IdTCPServer1.Bindings.Add;
  //Binding.IPVersion := Id_IPv4;   <----- Gives compilation error Error: Identifier not found "Id_IPv4"
  {$ENDIF}
  Binding.IP := '127.0.0.1';
  Binding.Port := 6501;
  IdTCPServer1.Active := True;
end;

end.

这是程序的项目文件 squares.lpr

program squares;

{$mode objfpc}{$H+}
// The following line is is necessary for Linux thread support            
{$IFDEF UNIX}{$DEFINE UseCThreads}{$ENDIF}     

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms, uSquares
  { you can add units after this };

{$R *.res}

begin
  RequireDerivedFormResource := True;
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

当我尝试使用 telnet 从终端连接到服务器时,我得到以下响应

telnet 127.0.0.1 6501
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
7
Connection closed by foreign host.

如您所见,telnet 连接到服务器。但是客户端连接后服务器的第一个响应“Type an integer and Enter”没有出现。此外,当我向服务器发送一个数字时,例如“7”要平方,telnet 说“连接被外国主机关闭”。所以 telnet 客户端也根本不会收到服务器的响应。我使用的是 Indy svn 版本,所以这不是旧 Indy 版本的问题。

因此,即使是这个基本示例也无法在 Linux 中运行!我不知道如何解决这个问题,所以我真的需要你的帮助。此外,如果您有任何我可以阅读的关于使用 Pascal 在 Linux 上进行套接字编程的资料,我将不胜感激。

我在 Linux Mint 上使用 Lazarus 0.9.31/FPC 2.4.4 和 Indy 10.5.8。

杰丹尼尔

【问题讨论】:

    标签: linux delphi client-server freepascal indy10


    【解决方案1】:

    Id_IPv4 在 IdGlobal.pas 中定义,请确保该单位在您的 uses 子句中。请注意,您仅在定义了 UNIX 时才调用 Bindings.Add(),但您尝试访问 IFDEF 块之外的 Binding。您根本不需要 IFDEF 块。 Indy 默认使用 IPv4。

    关于通信问题,如果 FreePascal 正确调用 TIdIOHandler.WriteLn() 而不是某些控制台 WriteLn() I/O 例程,我认为您显示的代码没有任何问题。可以显示客户端代码吗?

    服务器端,如果你设置了TIdIOHandler.DefStringEncoding属性或全局GIdDefaultEncoding变量为非默认编码。在非 Windows 系统上,TIdTextEncoding 使用 iconv 库,并且已知 Indy 的 iconv 支持现在有点错误。另一方面,Indy 的默认编码是 ASCII,根本不依赖 iconv,所以使用它应该不会有任何故障。

    【讨论】:

    • 感谢雷米的回复。 a) 客户端是上面的 telnet 输出。我使用 telnet 作为客户端来测试服务器,因此没有客户端代码。 b) 我根本没有更改默认编码状态,因为这个简单的服务器所要做的就是将数字的平方发送到 telnet 客户端。既然是这种情况,问题就出在其他地方。不过,我会调查 FreePascal 调用 TIOHandler.WriteLn 的方式,并会及时通知您。
    【解决方案2】:

    @Remy Lebeau。我找到了答案。我一直在玩文本编码,直到我得到下面的代码:

    procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
    var
      s: string;
      i: Integer;
    begin
      with AContext.Connection.IOHandler do
      try
        {$IFDEF UNIX}
        DefStringEncoding := TIdTextEncoding.Default
        {$ENDIF}
        WriteLn('Type an integer and Enter');
        s := ReadLn;
        try
          i := StrToInt(s);
          WriteLn(s + ' squared is ' + IntToStr(i*i));
        except
          WriteLn(s + ' is not an integer');
        end;
      finally
        Free;
      end;
    end;
    
    procedure TForm1.FormActivate(Sender: TObject);
    var
      Binding: TIdSocketHandle;
    begin
      {$IFDEF UNIX}
      Binding := IdTCPServer1.Bindings.Add;
      Binding.Port := 6501;
      {$ENDIF}
      {IFDEF MSWINDOWS}
      IdTCPServer1.DefaultPort := 6501
      {$ENDIF} 
      IdTCPServer1.Active := True;
    end;
    

    这是远程登录响应:

    telnet 127.0.0.1 6501
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    Type an integer and Enter
    7
    7 squared is 49
    Connection closed by foreign host.
    

    但是,我仍然想知道如何设置全局 GIdDefaultEncoding 变量,以便取消 DefStringEncoding := TIDTextEncoding.Default。感谢您的帮助。

    【讨论】:

    • 你仍然不需要 IFDEF
    • 您仍然不需要 IFDEF。 BindingsDefaultPort 属性在 Windows 和 Linux 中的工作方式完全相同。至于GIdDefaultEncoding,你可以像设置任何其他变量一样设置它,例如:IdGlobal.GIdDefaultEncoding := encOSDefault;,但它只有在TIdIOHandler.DefStringEncoding 为nil 时才生效,默认情况下它不是,所以无论如何你都必须为其赋值。为什么使用TIdTextEncoding.Default 有效,但TIdTextEncoding.ASCII 的默认分配无效。
    • 顺便说一句,你为什么在 IOHandler 上调用Free()?如果您想关闭连接,请致电AContext.Connection.Disconnect()。如果您想保持连接打开以便客户端可以发送更多命令,只需退出OnExecute 事件处理程序并让TIdTCPServer 再次触发它(它在连接的生命周期内循环触发)。 IOHandler.DefStringEncoding 属性的分配应该在 OnConnect 事件中完成。
    • 是的。我在服务器 OnExecute 过程中不需要它,但在 FormActivate 过程中确实需要它,因为 Windows 无法编译带有“Binding”的语句。我不知道为什么默认的“TIdTextEncoding.ASCII”不起作用。这对我来说是个谜。至于其余的,我会根据您的建议更新代码。
    • Bindings 集合在 Windows 中运行良好。我从来没有遇到过任何编译器问题。究竟什么不适合你?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多