升级Delphi 7 Indy 9应用程序。到Indy 10

时间:2016-10-18 17:21:35

标签: delphi indy10

我继承了一个广泛的(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 个答案:

答案 0 :(得分:4)

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

  1. 清除TIdCommandHandler的{​​{1}}和ReplyNormal属性(这也适用于Indy 9,除了ExceptionReplyExceptionReply之外版本),以及服务器的ReplyExceptionCode属性(仅限Indy 10)。

  2. CommandHandlers.ExceptionReply处理程序中将TIdCommand.PerformReply属性设置为false(这也适用于Indy 9):

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

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

    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

    话虽如此,任何这些方法都可以正常工作,而无需更改现有的客户端代码。但是,在Indy 10中,我建议直接使用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; 代替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; 没有收到SendCmd()回复,您可以让SUCCESS提出异常:

    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()的使用不是线程安全的。使用TThread.Synchronize()TThread.Queue()TIdSyncTIdNotify等技术,对UI 的任何访问都必须与主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()函数具有类似的线程安全性(如果尚未安装)。