Indy TCPClient OnDisconnect 事件不起作用
type
TForm8 = class(TForm)
idtcpclnt1: TIdTCPClient;
idtcpsrvr1: TIdTCPServer;
procedure FormCreate(Sender: TObject);
procedure idtcpsrvr1Execute(AContext: TIdContext);
procedure idtcpclnt1Disconnected(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form8: TForm8;
implementation
{$R *.dfm}
procedure TForm8.FormCreate(Sender: TObject);
begin
idtcpclnt1.Connect;
end;
procedure TForm8.idtcpsrvr1Execute(AContext: TIdContext);
begin
AContext.Connection.Disconnect(true); //this gets called
end;
procedure TForm8.idtcpclnt1Disconnected(Sender: TObject);
begin
ShowMessage('true'); //but this does not
end;
OnDC 永远不会被处理。为什么?
type
TForm8 = class(TForm)
idtcpclnt1: TIdTCPClient;
idtcpsrvr1: TIdTCPServer;
procedure FormCreate(Sender: TObject);
procedure idtcpsrvr1Execute(AContext: TIdContext);
procedure idtcpclnt1Disconnected(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form8: TForm8;
implementation
{$R *.dfm}
procedure TForm8.FormCreate(Sender: TObject);
begin
idtcpclnt1.Connect;
end;
procedure TForm8.idtcpsrvr1Execute(AContext: TIdContext);
begin
AContext.Connection.Disconnect(true); //this gets called
end;
procedure TForm8.idtcpclnt1Disconnected(Sender: TObject);
begin
ShowMessage('true'); //but this does not
end;
The OnDC never gets handled. Why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Indy 客户端组件不是事件驱动的(有几个例外,例如
TIdTelnet
)。当服务器断开连接时,不会触发 TIdTCPClient.OnDisconnect 事件,就像您假设的那样。这是设计使然。TIdTCPClient
在尝试再次访问套接字之前不会知道断开连接,此时它会引发异常,例如EIdConnClosedGraceously
。仅当在客户端调用TIdTCPClient.Disconnect()
方法时才会触发TIdTCPClient.OnDisconnect
事件,而您并未执行此操作。为了检测服务器端与
TIdTCPClient
的断开连接,您必须定期从套接字读取数据,例如在计时器或单独的线程中。Indy client components are not event-driven (with a couple of exceptions, such as
TIdTelnet
). TheTIdTCPClient.OnDisconnect
event is NOT triggered when the server disconnnects on its end, like you are assuming. This is by design.TIdTCPClient
will not know about the disconnection until it tries to access the socket again, at which time it will raise an exception, such asEIdConnClosedGracefully
. TheTIdTCPClient.OnDisconnect
event is only triggered when theTIdTCPClient.Disconnect()
method is called on the client side, which you are not doing.In order to detect server-side disconnects with
TIdTCPClient
, you have to read from the socket periodically, such as in a timer or a separate thread.好吧,我的错。你的代码不起作用,但这是正确的。让我解释一下原因:
AContext.Connection.Disconnect(true)
方法调用 TCPServer 中未实现的DisconnectNotifyPeer
。为什么?因为不应该。当您在服务器中断开连接时,indy 所做的就是使套接字无效并关闭它。客户端只有在尝试发送某些请求时才会注意到服务器已断开连接。而你的代码并没有这样做。这是 indy 的默认行为。
为了通知客户端服务器已断开连接,indy 和任何其他套件应该实现我们所说的
heartbeat
。心跳是一种时不时地尝试向套接字发送小数据包以检测它是否仍然存在的技术。检测套接字断开连接的唯一方法是尝试在该套接字中写入内容。谷歌一下heartbeat
,你就会明白我的意思。编辑
检查此。
Ok, my mistake. You code does not work, but that is correct. Let me explain why:
The
AContext.Connection.Disconnect(true)
method callsDisconnectNotifyPeer
wich is not implemented in TCPServer. Why? Because it should not.When you disconnect in the server, what indy does is invalidate the socket and close it. The client will only notice that the server disconnected when it tries to send some request. And you code does not do that. This is a default behavior of indy.
In order to notify the client that the server disconnected, indy and any other suites should implement what we call
heartbeat
. Heartbeat is a technique that from time to time tries to send small packets to an socket in order to detect that it is still alive. The only way of detect a socket disconnection is trying to write something in that socket. Google aboutheartbeat
and you will understand what I mean.EDIT
Check this out.
您可以通过向客户端添加计时器例程来使客户端轮询断开连接 - 这是最简单的方法。
这应该使代码的行为就像旧的 TClientSocket 一样(并且像 TidTelnet 一样)。如果服务器突然消失(即一旦触发定时器例程检测到这种情况),它会为 OnStatus 事件生成一个 hsDisconnected 标志。但是,这种导致断开连接的服务器丢失的特殊情况不会触发 OnDisconnect 事件 - 只是触发 OnStatus。因此,最好始终使用 OnStatus 来捕获所有断开连接,无论是客户端还是服务器引起的。我使用了一个设置为 100 毫秒的计时器,但我想你可以根据需要将其设置为频繁或缓慢 - 它似乎不会造成任何损害。
注意:对于 DELPHI 7(可能还有 D7 和 XE4 之间的其他版本),您必须以稍微不同的方式执行此操作:
顺便说一句 - 如果您使用 Delphi 6,请忘记 Indy,它当时的 bug 太多了。
You can make the client POLL for disconnection by adding a timer routine to the client - this is the SIMPLEST way.
This should make the code behave just like the old TClientSocket used to (and like the TidTelnet does). It produces a hsDisconnected flag to the OnStatus event if the server suddenly disappears (i.e. as soon as the firing timer routine detects this). However, this special case of server-loss causing the disconnect does NOT fire the OnDisconnect event - just the OnStatus. So it is probably better to always use OnStatus to trap all disconnections, be they client or server induced. I used a timer set at 100ms, but I guess you can make it as frequent or slow as you want - it doesn't appear to do any harm.
NOTE: FOR DELPHI 7 (and possibly other versions between D7 and XE4), you will have to do this slightly differently:
By the way - if you're using Delphi 6, forget Indy, it was just way too buggy back then.