问题描述
我想为我的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;
解决方法
从Indy帮助中我了解到...
帮助太旧了,信息已经过时了。
我必须使用
CreateIOHandler
并指定我的自定义IOHandler类。
您可以这样做,但实际上并不需要。您可以在调用TIdTCPClient.IOHandler
之前直接将自定义类的实例直接分配给TIdTCPClient.Connect()
属性,例如:
TCPClient := TIdTCPClient.Create;
TCPClient.IOHandler :- TIdEnhancedIOHandler.Create(TCPClient);
...
我这样做了,但出现一个异常,提示未安装此类。
这意味着Indy内部的GIOHandlerClassList
不包含任何从您指定给CreateIOHandler()
的类类型派生的类类型。
如何安装?保存列表的变量
GIOHandlerClassList
是私有的...
您需要在运行时以自定义类类型调用公共RegisterIOHandler()
或SetDefaultClass()
类方法,例如在您单位的initialization
部分,例如:
initialization
TIdEnhancedIOHandler.RegisterIOHandler();
但是,Indy中唯一实际使用CreateIOHandler()
的东西是TIdSimpleServer
,因此在这种情况下无需“注册”您的自定义类。
另一方面,如果未分配TIdTCPClient.Connect()
,TIdIOHandler.MakeDefaultIOHandler()
会调用IOHandler
,并使用GIOHandlerClassDefault
(由TIdIOHandler.SetDefaultClass()
设置(也称为RegisterIOHandler()
)。因此,如果您希望TIdTCPClient
为您创建自定义类类型的对象,则至少需要调用SetDefaultClass()
,例如:
initialization
TIdEnhancedIOHandler.SetDefaultClass();
无论哪种方式,RegisterIOHandler()
/ SetDefaultClass()
只能被调用一次,例如在程序启动时。
更新:您收到一个抽象错误,因为您是从TIdIOHandlerSocket
(它是一个抽象类)派生您的类的,因为它没有实现在ReadDataFromSource()
中声明为WriteDataToTarget()
的{{1}}和abstract
方法。您需要改为从TIdIOHandler
派生您的类,而该类又从TIdIOHandlerStack
派生并实现这些方法。