如何设置 Indy 自定义 TIdIOHandler?

How to setup an Indy custom TIdIOHandler?

我想为我的 Indy TCP 客户端使用自定义 TIdIOHandler,但我不知道如何设置它。我创建了一个新的 IOHandler class,我注册了 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;

From the Indy Help I understand that ...

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

I must use CreateIOHandler and specify my custom IOHandler class.

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

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

I do that and I get an exception which says that this class is not installed.

这意味着 Indy 的内部 GIOHandlerClassList 不包含任何派生自您指定给 CreateIOHandler().

的 class 类型的 class 类型

How cand I install it ? The variable GIOHandlerClassList that holds the list is private...

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

initialization
  TIdEnhancedIOHandler.RegisterIOHandler();

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

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

initialization
  TIdEnhancedIOHandler.SetDefaultClass();

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


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