繁体   English   中英

升级Delphi 7 Indy 9应用程序。 前往印第10

[英]Upgrading Delphi 7 Indy 9 app. to Indy 10

我继承了一个广泛的(199个命令)Delphi 7 Indy 9应用程序,该应用程序正在升级到Indy 10(在D10.1中)。 我已经升级了所有代码,并且可以编译并运行。 遇到的问题是,现在在Indy 10中,除了在Indy 9下执行的编码响应之外,所有处理程序还返回响应代码 (和文本)。

例如:

// server 
procedure TFormMain.IdCmdTCPServer1loginCommand(ASender: TIdCommand);
var
  Rights: String;
begin

   if BillingUserRegistered(ASender.Params[0], ASender.Params[1], Rights) then
   begin
      myClient := TClientData.Create;
      myClient.ClientName := ASender.Params[0];
      myClient.ClientHost := #32; // indy9 was .Thread.Connection.LocalName; 
      myClient.ID := Now;
      ASender.Context.Data := myClient;

      ListBox1.Items.AddObject(
        PadR(myClient.ClientName,12,' ') + '=' +
        FormatDateTime('yyyy-mm-dd hh:nn:ss', myClient.ID),
        TDateTimeO.Create(myClient.ID));
      ASender.Context.Connection.IOHandler.WriteLn('SUCCESS' + ' ' + Rights)  
  end
  else
      ASender.Context.Connection.IOHander.WriteLn('Login failed!');

end;

...

// client side
function TfrmLogin.VerifyUserNameAndPassword(username, password: String): Boolean;
var
  response, response1: String;
begin

  frmMain.IdTCPClient1.IOHandler.WriteLn('login' + ' ' + 
     username + ' ' + password)
  response := frmMain.IdTCPClient1.IOHandler.ReadLn();
  // I have to add this now to capture the response code too!
  response1 := frmMain.IdTCPClient1.IOHandler.ReadLn(); // 200 OK
  // ------------------------------------------------------
  if Copy(response,1,7) = 'SUCCESS' then
  begin
    rights := Copy(response,9,4);

有很多命令处理程序,它们都有自己的自定义响应。 在客户端需要更改很多代码。 如果命令处理程序已经提供了自己的命令,是否可以告诉IdCmdTCPServer禁止标准的“ 200 OK”响应? 还是我待了一个晚上?

谢谢

如果需要取消默认命令响应,则可以:

  1. 清除TIdCommandHandlerReplyNormalExceptionReply属性(这在Indy 9中也适用,除了ExceptionReply在该版本中是ReplyExceptionCode ),以及服务器的CommandHandlers.ExceptionReply属性(仅Indy 10)。

  2. OnCommand处理程序中将TIdCommand.PerformReply属性设置为false(在Indy 9中也可以使用):

     procedure TFormMain.IdCmdTCPServer1loginCommand(ASender: TIdCommand); var ... begin ASender.PerformReply := False; ... end; 
  3. 将服务器的CommandHandlers.PerformReplies属性设置为false(仅限Indy 10-默认情况下,它将把TIdCommand.PerformReply设置为false):

     IdCmdTCPServer1.CommandHandlers.PerformReplies := False; 

另一方面,您应该考虑使用命令处理程序响应来设计它们的使用方式,例如:

procedure TFormMain.IdCmdTCPServer1loginCommand(ASender: TIdCommand);
var
  Rights: String;
begin
  if ASender.Params.Count = 2 then
  begin
    if BillingUserRegistered(ASender.Params[0], ASender.Params[1], Rights) then
    begin
      ...
      ASender.Reply.SetReply('SUCCESS', Rights);
    end
    else
      ASender.Reply.SetReply('ERROR', 'Login failed!');
  end
  else
    ASender.Reply.SetReply('ERROR', 'Wrong number of parameters!');
end;

我什至可以说应该将TIdCommandHandler.NormalReply.Code属性设置为SUCCESS ,并将TIdCommandHandler.ExceptionReply.Code属性设置为ERROR ,然后可以在OnCommand处理程序中执行此操作:

procedure TFormMain.IdCmdTCPServer1loginCommand(ASender: TIdCommand);
var
  Rights: String;
begin
  if ASender.Params.Count <> 2 then
    raise Exception.Create('Wrong number of parameters!');

  if not BillingUserRegistered(ASender.Params[0], ASender.Params[1], Rights) then
    raise Exception.Create('Login failed!');

  ...

  ASender.Text.Text := Rights;
end;

话虽如此,任何这些方法都可以在不更改现有客户端代码的情况下正常工作。 但是,在Indy 10中,我建议直接使用SendCmd()而不是WriteLn() / ReadLn()

function TfrmLogin.VerifyUserNameAndPassword(username, password: String): Boolean;
var
  response: String;
begin
  response := frmMain.IdTCPClient1.SendCmd('login ' + username + ' ' + password);
  if response = 'SUCCESS' then
  begin
    rights := frmMain.IdTCPClient1.LastCmdResult.Text.Text;
    ...
  end else begin
    // error message in frmMain.IdTCPClient1.LastCmdResult.Text.Text ...
  end;
end;

另外,如果未收到SUCCESS答复,则可以让SendCmd()引发异常:

function TfrmLogin.VerifyUserNameAndPassword(username, password: String): Boolean;
begin
  try
    frmMain.IdTCPClient1.SendCmd('login ' + username + ' ' + password, 'SUCCESS');
  except
    on E: EIdReplyRFCError do begin
      // error message in E.Message ...
      ...
      Exit;
    end;
  end;

  rights := frmMain.IdTCPClient1.LastCmdResult.Text.Text;
  ...
end;

Indy 9中确实存在SendCmd() ,但它仅支持您不使用的基于数字的响应代码。 从上面可以看到,Indy 10中的SendCmd()支持基于字符串的响应代码以及数字响应代码。


附带说明:在服务器代码中, OnCommand处理程序在工作线程中运行,因此对ListBox1.Items.AddObject()使用不是线程安全的。 对UI的任何访问都必须使用TThread.Synchronize()TThread.Queue()TIdSyncTIdNotify等技术与主UI线程同步,例如:

procedure TFormMain.IdCmdTCPServer1loginCommand(ASender: TIdCommand);
var
  Rights: String;
  myClient: TClientData;
begin
  if ASender.Params.Count = 2 then
  begin
    if BillingUserRegistered(ASender.Params[0], ASender.Params[1], Rights) then
    begin
      myClient := TClientData(ASender.Context.Data);
      if myClient = nil then
      begin
        myClient := TClientData.Create;
        ASender.Context.Data := myClient;
      end;

      myClient.ID := Now;
      myClient.ClientName := ASender.Params[0];

      myClient.ClientHost := GStack.HostByAddress(ASender.Context.Binding.PeerIP, ASender.Context.Binding.IPVersion);
      // In Indy 9, this would be:
      // myClient.ClientHost := GStack.WSGetHostByAddr(ASender.Thread.Connection.Socket.PeerIP);
      // NOT ASender.Thread.Connection.LocalName!

      TThread.Queue(nil,
        procedure
        begin
          ListBox1.Items.AddObject(
            PadR(myClient.ClientName,12,' ') + '=' + FormatDateTime('yyyy-mm-dd hh:nn:ss', myClient.ID),
            TDateTimeO.Create(myClient.ID));
        end
      );

      ASender.Reply.SetReply('SUCCESS', Rights);
    end
    else
      ASender.Reply.SetReply('ERROR', 'Login failed!');
  end
  else
    ASender.Reply.SetReply('ERROR', 'Wrong number of parameters!');
end;

如果还没有,请确保BillingUserRegistered()函数同样具有线程安全性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM