IP黑名单TcpServer

时间:2017-03-15 20:42:53

标签: delphi

我如何限制每个ip的连接?我试过这段代码how to block unknown clients in indy (Delphi),但如果我的服务器被洪水淹没,我无法连接。来自Remy的代码只是阻止CPU使用100%并使用更多内存。但是洪水的连接仍然在tcpserver上运行,我无法连接到服务器。所以我的问题是,如何在onconnect之前限制连接,使用tcpserver接受什么?也许挂钩接受功能并尝试限制连接?

1 个答案:

答案 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属性。