升级Delphi 7 Indy 9应用程序.前往Indy 10 [英] Upgrading Delphi 7 Indy 9 app. to Indy 10

查看:144
本文介绍了升级Delphi 7 Indy 9应用程序.前往Indy 10的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have inherited an extensive (199 commands) Delphi 7 Indy 9 app that I am upgrading to Indy 10 (in 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.

例如:

// 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"响应?还是我待了一个晚上?

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? Or am I in for a long night?

谢谢

推荐答案

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

If you need to suppress the default command responses, you can either:

  1. 清除 TIdCommandHandler ReplyNormal ExceptionReply 属性(在Indy 9中也适用,除了 ExceptionReply是该版本中的 ReplyExceptionCode )和服务器的 CommandHandlers.ExceptionReply 属性(仅适用于Indy 10).

  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).

在您的 OnCommand 处理程序中将 TIdCommand.PerformReply 属性设置为false(在Indy 9中也适用):

set the TIdCommand.PerformReply property to false in your OnCommand handler (this also works in Indy 9):

procedure TFormMain.IdCmdTCPServer1loginCommand(ASender: TIdCommand);
var
  ...
begin
  ASender.PerformReply := False;
  ...
end;

  • 将服务器的 CommandHandlers.PerformReplies 属性设置为false(仅限Indy 10-默认情况下,它将 TIdCommand.PerformReply 设置为false):

  • set the server's CommandHandlers.PerformReplies property to false (Indy 10 only - it will set TIdCommand.PerformReply to false by default):

    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;
    

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

    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:

    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():

    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:

    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()引发异常:

    Alternatively, you can let SendCmd() raise an exception if it does not receive a SUCCESS reply:

    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()在Indy 9中确实存在,但是它仅支持您不使用的基于数字的响应代码.如上所示,Indy 10中的 SendCmd()支持基于字符串的响应代码以及数字响应代码.

    SendCmd() does exist in Indy 9, but it only supports numeric-based response codes, which you are not using. As you can see above, SendCmd() in Indy 10 supports string-based response codes as well as numeric ones.

    附带说明:在您的服务器代码中, OnCommand 处理程序在工作线程中运行,因此您对 ListBox1.Items.AddObject()的使用不是线程-安全的.使用 TThread.Synchronize() TThread.Queue() TIdSync TIdNotify 等,例如:

    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. Any access to the UI must be synchronized with the main UI thread, using techniques like TThread.Synchronize(), TThread.Queue(), TIdSync, TIdNotify, etc, eg:

    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()函数具有线程安全性(如果尚未安装).

    Make sure your BillingUserRegistered() function is similarly thread-safe, if it is not already.

    这篇关于升级Delphi 7 Indy 9应用程序.前往Indy 10的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆