我如何限制每个ip的连接?我试过这段代码how to block unknown clients in indy (Delphi),但如果我的服务器被洪水淹没,我无法连接。来自Remy的代码只是阻止CPU使用100%并使用更多内存。但是洪水的连接仍然在tcpserver上运行,我无法连接到服务器。所以我的问题是,如何在onconnect之前限制连接,使用tcpserver接受什么?也许挂钩接受功能并尝试限制连接?
答案 0 :(得分:6)
我如何限制每个ip的连接?
您已经知道答案,因为这正是the other code正在做的事情。
如果我的服务器被淹没,我无法连接。
其他代码的目的只是将客户端IP地址限制为最多10个并发连接,而不是为了防止泛洪或降低CPU / RAM使用率。除非停用服务器或设置其MaxConnections
属性,否则无法阻止不需要的客户端连接到服务器。除此之外,您可以做的就是尽快断开不需要的客户端,您可以在服务器的OnConnect
事件中执行此操作。但是如果你被淹没,那将需要时间来处理,特别是如果你不断锁定和解锁服务器的Contexts
列表,这将最终序列化服务器的内部线程。
洪水管理确实需要由防火墙或路由器/负载均衡器处理,而不是在服务器应用程序本身中处理。如果您不接受这一点,那么至少在Windows上,一个选项可能是编写一个自定义TIdServerIOHandlerStack
派生组件来覆盖虚拟Accept()
方法以调用WinSock的WSAAccept()
函数,它提供了一个回调,您可以使用它在离开接受队列之前拒绝连接,因此TIdTCPServer
不会看到它们。例如:
type
TMyServerIOHandler = class(TIdServerIOHandlerStack)
public
function Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler; override;
end;
function MyConditionFunc(lpCallerId, lpCallerData: LPWSABUF; lpSQOS, lpGQOS: LPQOS; lpCalleeId, lpCalleeData: LPWSABUF; g: PGROUP dwCallbackData: DWORD_PTR): Integer; stdcall;
begin
if (the address stored in lpCallerId is blocked) then
Result := CF_REJECT
else
Result := CF_ACCEPT;
end;
type
TIdSocketHandleAccess = class(TIdSocketHandle)
end;
function TMyServerIOHandler.Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler;
var
LIOHandler: TIdIOHandlerSocket;
LBinding: TIdSocketHandle;
LAcceptedSocket: TIdStackSocketHandle;
begin
Result := nil;
LIOHandler := TIdIOHandlerStack.Create(nil);
try
LIOHandler.Open;
while not AListenerThread.Stopped do
begin
if ASocket.Select(250) then
begin
LBinding := LIOHandler.Binding;
LBinding.Reset;
LAcceptedSocket := WSAAccept(ASocket.Handle, nil, nil, @MyConditionFunc, 0);
if LAcceptedSocket <> Id_INVALID_SOCKET then
begin
TIdSocketHandleAccess(LBinding).SetHandle(LAcceptedSocket);
LBinding.UpdateBindingLocal;
LBinding.UpdateBindingPeer;
LIOHandler.AfterAccept;
Result := LIOHandler;
LIOHandler := nil;
Break;
end;
end;
end;
finally
FreeAndNil(LIOHandler);
end;
end;
然后,您可以在激活服务器之前将TMyServerIOHandler
的实例分配给TIdTCPServer.IOHandler
属性。