简体   繁体   English

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

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

I have inherited an extensive (199 commands) Delphi 7 Indy 9 app that I am upgrading to Indy 10 (in D10.1). 我继承了一个广泛的(199个命令)Delphi 7 Indy 9应用程序,该应用程序正在升级到Indy 10(在D10.1中)。 I have upgraded all the code, and it compiles and runs. 我已经升级了所有代码,并且可以编译并运行。 The problem I have is that now in Indy 10 all the handlers also return a response code (and text) in addition to the coded response that they did under Indy 9. 遇到的问题是,现在在Indy 10中,除了在Indy 9下执行的编码响应之外,所有处理程序还返回响应代码 (和文本)。

For example: 例如:

// 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);

There are a lot of command handlers, and they all have their own custom responses. 有很多命令处理程序,它们都有自己的自定义响应。 That's a lot of code to change at the client. 在客户端需要更改很多代码。 Is there a way I can tell the IdCmdTCPServer to suppress the standard '200 Ok' response if the command handler already provides it's own? 如果命令处理程序已经提供了自己的命令,是否可以告诉IdCmdTCPServer禁止标准的“ 200 OK”响应? Or am I in for a long night? 还是我待了一个晚上?

Thanks 谢谢

If you need to suppress the default command responses, you can either: 如果需要取消默认命令响应,则可以:

  1. clear the TIdCommandHandler 's ReplyNormal and ExceptionReply properties (this also works in Indy 9, except that ExceptionReply was ReplyExceptionCode in that version), and the server's CommandHandlers.ExceptionReply property (Indy 10 only). 清除TIdCommandHandlerReplyNormalExceptionReply属性(这在Indy 9中也适用,除了ExceptionReply在该版本中是ReplyExceptionCode ),以及服务器的CommandHandlers.ExceptionReply属性(仅Indy 10)。

  2. set the TIdCommand.PerformReply property to false in your OnCommand handler (this also works in Indy 9): OnCommand处理程序中将TIdCommand.PerformReply属性设置为false(在Indy 9中也可以使用):

     procedure TFormMain.IdCmdTCPServer1loginCommand(ASender: TIdCommand); var ... begin ASender.PerformReply := False; ... end; 
  3. set the server's CommandHandlers.PerformReplies property to false (Indy 10 only - it will set TIdCommand.PerformReply to false by default): 将服务器的CommandHandlers.PerformReplies属性设置为false(仅限Indy 10-默认情况下,它将把TIdCommand.PerformReply设置为false):

     IdCmdTCPServer1.CommandHandlers.PerformReplies := False; 

On the other hand, you should consider using the command handler responses the way they are designed to be used, eg: 另一方面,您应该考虑使用命令处理程序响应来设计它们的使用方式,例如:

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;

I would even go as far as saying that you should set the TIdCommandHandler.NormalReply.Code property to SUCCESS and the TIdCommandHandler.ExceptionReply.Code property to ERROR , and then you can do this inside your OnCommand handler: 我什至可以说应该将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;

With that said, any of these approaches should work fine without changing your existing client code. 话虽如此,任何这些方法都可以在不更改现有客户端代码的情况下正常工作。 However, in Indy 10, I would suggest using SendCmd() instead of WriteLn() / ReadLn() directly: 但是,在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;

Alternatively, you can let SendCmd() raise an exception if it does not receive a SUCCESS reply: 另外,如果未收到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;

SendCmd() does exist in Indy 9, but it only supports numeric-based response codes, which you are not using. Indy 9中确实存在SendCmd() ,但它仅支持您不使用的基于数字的响应代码。 As you can see above, SendCmd() in Indy 10 supports string-based response codes as well as numeric ones. 从上面可以看到,Indy 10中的SendCmd()支持基于字符串的响应代码以及数字响应代码。


On a side note: in your server code, the OnCommand handler runs in a worker thread, so your use of ListBox1.Items.AddObject() is not thread-safe. 附带说明:在服务器代码中, OnCommand处理程序在工作线程中运行,因此对ListBox1.Items.AddObject()使用不是线程安全的。 Any access to the UI must be synchronized with the main UI thread, using techniques like TThread.Synchronize() , TThread.Queue() , TIdSync , TIdNotify , etc, eg: 对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;

Make sure your BillingUserRegistered() function is similarly thread-safe, if it is not already. 如果还没有,请确保BillingUserRegistered()函数同样具有线程安全性。

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

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