【问题标题】:How to setup an Indy custom TIdIOHandler?如何设置 Indy 自定义 TIdIOHandler?
【发布时间】:2020-11-10 18:16:16
【问题描述】:

我想为我的 Indy TCP 客户端使用自定义 TIdIOHandler,但我不知道如何设置它。我创建了一个新的 IOHandler 类,注册了TIdIOHandler.RegisterIOHandler,然后我将TIdTCPClient.CreateIOHandler 与我的新处理程序引用一起使用。现在,当我尝试写信给TIdTCPClient.Socket 时,我得到“抽象错误”异常...除了我的示例之外,我还需要配置其他东西吗?

  TIdEnhancedIOHandler = class(TIdIOHandlerSocket)
  public
    function Acknowledge(Command: Cardinal = 0): Boolean;
  end

{this is a client in a thread}
constructor TMyTCPClient.Create(const AHost: String; APort: Word);
begin
 inherited Create;
 FreeOnTerminate:= True;
 TIdEnhancedIOHandler.RegisterIOHandler;
 TCPClient:= TIdTCPClient.Create;
 TCPClient.CreateIOHandler(TIdEnhancedIOHandler);
 TCPClient.ConnectTimeout:= 1000;
 TCPClient.ReadTimeout:= -1;
 TCPClient.Host:= AHost;
 TCPClient.Port:= APort;
 RetSuccess:= False;
 RetMessage:= 'Unknown error.';
end;

procedure TMainClient.Execute;
var CMD: Cardinal;
begin
 TCPClient.Connect;
 TCPClient.Socket.Write(CMD);
end;

【问题讨论】:

    标签: delphi indy delphi-10.3-rio


    【解决方案1】:

    从 Indy Help 我了解到...

    帮助是旧的,并且有过时的信息。

    我必须使用 CreateIOHandler 并指定我的自定义 IOHandler 类。

    你可以这样做,但实际上你不需要这样做。在调用TIdTCPClient.Connect() 之前,您可以简单地将自定义类的实例直接分配给TIdTCPClient.IOHandler 属性,例如:

    TCPClient := TIdTCPClient.Create;
    TCPClient.IOHandler :- TIdEnhancedIOHandler.Create(TCPClient);
    ...
    

    我这样做了,我得到一个异常,说这个类没有安装。

    这意味着 Indy 的内部 GIOHandlerClassList 不包含任何从您指定给 CreateIOHandler() 的类类型派生的类类型。

    我该如何安装它?保存列表的变量GIOHandlerClassList 是私有的...

    您需要在运行时调用自定义类类型的公共 RegisterIOHandler()SetDefaultClass() 类方法,例如在您单元的 initialization 部分中,例如:

    initialization
      TIdEnhancedIOHandler.RegisterIOHandler();
    

    然而,Indy 中唯一真正使用CreateIOHandler() 的是TIdSimpleServer,因此在这种情况下无需“注册”您的自定义类。

    另一方面,如果没有分配IOHandlerTIdTCPClient.Connect() 会调用TIdIOHandler.MakeDefaultIOHandler(),并且使用由TIdIOHandler.SetDefaultClass() 设置的GIOHandlerClassDefault(也调用RegisterIOHandler())。因此,如果您希望 TIdTCPClient 为您创建自定义类类型的对象,您至少需要调用 SetDefaultClass(),例如:

    initialization
      TIdEnhancedIOHandler.SetDefaultClass();
    

    无论哪种方式,RegisterIOHandler()/SetDefaultClass() 都应该只调用一次,例如在程序启动时。


    更新:您收到一个抽象错误,因为您从TIdIOHandlerSocket 派生您的类,这是一个抽象 类,因为它没有实现@987654347在TIdIOHandler 中声明为abstract 的@ 和WriteDataToTarget() 方法。您需要从 TIdIOHandlerStack 派生您的类,它从 TIdIOHandlerSocket 派生并实现这些方法。

    【讨论】:

    • 抱歉,您写答案时我正在编辑问题。我使用SetDefaultClass 并成功创建了处理程序......但是现在,当我尝试读取/写入 TCPClient.Socket 时,我收到一条异常消息“抽象错误”
    • 太好了,就是这样!谢谢!
    • 但我看不到 AcknowledgeTCPClient.SocketTCPClient.IOHandler 中的功能...
    • IOHandler 属性是 TIdIOHandlerSocket 属性是 TIdIOHandlerSocketAcknowledge() 不是任一类的成员。您必须进行类型转换才能访问它:TIdEnhancedIOHandler(TCPClient.IOHandler).Acknowledge(...)TIdEnhancedIOHandler(TCPClient.Socket).Acknowledge(...)。在这种情况下,让TIdEnhancedIOHandler 成为class helper 而不是后代可能更有意义,那么您就不需要类型转换:TCPClient.IOHandler.Acknowledge(...)
    猜你喜欢
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多