1

我有一个问题让我陷入困境。我正在尝试将 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。

丹尼尔

4

2 回答 2

2

Id_IPv4 is defined in IdGlobal.pas, make sure that unit is in your uses clause. Note that you are calling Bindings.Add() only if UNIX is defined, but you are attempting to access the Binding outside of the IFDEF block. You don't need the IFDEF block at all. Indy defaults to IPv4.

Regarding the communication issue, I see nothing wrong with the code you have shown, provided FreePascal is correctly calling TIdIOHandler.WriteLn() and not some console WriteLn() I/O routine. Can you show the client code?

Server-side, the only thing I can think of right now that might go wrong is a possible failure in Indy's TIdTextEncoding class when sending/receiving strings, if you have set the TIdIOHandler.DefStringEncoding property or the global GIdDefaultEncoding variable to a non-default encoding. On non-Windows systems, TIdTextEncoding uses the iconv library, and Indy's iconv support is known to be a bit buggy right now. On the other hand, Indy's default encoding is ASCII, which does not rely on iconv at all, so there should not be any failures using that.

于 2011-10-16T16:06:16.563 回答
0

@雷米勒博。我找到了答案。我一直在玩文本编码,直到我得到下面的代码:

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。感谢你的协助。

于 2011-10-16T22:37:34.733 回答