我有一个公共服务器(配置indy 10)。一些未知的客户端正在发送数以千计的无内容消息,它将服务器的CPU使用率更改为50%。我的服务器上没有防火墙,所以我试图使用以下代码阻止未知客户端:
这是一个与Timer配合使用的功能:
var
i, j: integer;
begin
IX2 := IX2 + 1;
SetLength(ClientIPs, IX2);
ClientIPs[IX2 - 1] := StrIP;
j := 0;
for i := low(ClientIPs) to high(ClientIPs) do
begin
Application.ProcessMessages;
if ClientIPs[i] = StrIP then
j := j + 1;
end;
if j > 10 then
begin
Result := false;
exit;
end;
Result := true;
这是我的计时器代码:
//Reset filtering measures
IX2 := 0;
SetLength(ClientIPs, 0);
所以我在OnExecute事件中使用它:
LogIP := AContext.Connection.Socket.Binding.PeerIP;
if IPFilter(LogIP) <> true then
begin
AContext.Connection.disconnect;
exit;
end;
//Get Data *********
Data := AContext.Connection.IOHandler.ReadLn();
最后,如果客户端在短时间内发送了许多消息,它将断开连接。但有一个问题 。事实上,在客户端断开连接之后,Onexecute事件仍在工作,我无法完全停止操作。但是我需要完全阻止某些IP。
谢谢
答案 0 :(得分:5)
OnConnect事件是断开黑名单IP的更好地方。在OnExecute事件中进行检查的唯一原因是,在OnConnect已被触发之前,IP是否未被列入黑名单。
至于为什么OnExecute在你断开连接后继续运行 - 唯一可能发生的方法是你的OnExecute处理程序有一个try..except块,它正在捕获并丢弃Indy的内部通知。您执行的任何异常处理都需要重新引发EIdException派生的异常,以便服务器可以处理它们。
答案 1 :(得分:4)
跟进我之前的评论:
function TForm1.IPFilter(const StrIP: string): Boolean;
var
i, j: integer;
list: TList;
begin
j := 0;
list := IdTCPServer1.Contexts.LockList;
try
for i := 0 to list.Count-1 do
begin
if TIdContext(list[i]).Binding.PeerIP = StrIP then
Inc(j);
end;
Result := j <= 10;
finally
IdTCPServer1.Contexts.UnlockList;
end;
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
// the simpliest way to force a disconnect and stop
// the calling thread is to raise an exception...
if not IPFilter(AContext.Binding.PeerIP) then
Abort();
// alternatively, if you call Disconnect(), make sure
// the IOHandler's InputBuffer is empty, or else
// AContext.Connection.Connected() will continue
// returning True!...
{if not IPFilter(AContext.Binding.PeerIP) then
begin
AContext.Connection.Disconnect;
AContext.Connection.IOHandler.InputBuffer.Clear;
Exit;
end;}
//Get Data *********
Data := AContext.Connection.IOHandler.ReadLn();
end;