0

i'm having some problems with flood on my TIdTcpServer and that are blocking the customers to connect at TIdTcpServer, Other problem is stuck connections at TIdTcpServer so we need restart the server application after some hours to back work, if not the clients don't connect.

This is my code at server side:

type
  TCommand = (
    CustomerConnect,
    CustomerDisconnect,
    CustomerNotification);

type
  TClient = record
    CustomerName : String[40];
    Notification : String[40];
end;

const
  szClient = SizeOf(TClient);

type
  TProtocol = record
    Command: TCommand;
    Sender: TClient;
    DataSize: Integer;
end;

const
  szProtocol = SizeOf(TProtocol);

type
  TClientContext = class(TIdServerContext)
  private
    FCriticalSection  : TCriticalSection;
    FClient           : TClient;
  public
    Queue             : TIdThreadSafeStringList;

    constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
    destructor Destroy; override;
  public
    procedure Lock;
    procedure Unlock;
  public
    property Client: TClient read FClient write FClient;
end;

i only use OnExecute method, who is these functions:

type
  PTBytes   = ^TBytes;
  PTIdBytes = ^TIdBytes;
var
  LBuffer     : TIdBytes;
  LProtocol   : TProtocol;
  FTempBuffer : TIdBytes;

  ToSend : TBytes;
  Protocol    : TProtocol;

  Con     : TClientContext;

  Queue       : TStringList;
  List        : TStringList;
  x           : Integer;
begin   
  Con := TClientContext(AContext);

  List := nil;
  try
    Queue := Con.Queue.Lock;
    try
      if Queue.Count > 0 then
      begin
        List := TStringList.Create;
        List.Assign(Queue);
        Queue.Clear;
      end;
    finally
      Con.Queue.Unlock;
    end;

    if List <> nil then
    begin
      Con.Lock;

      for x := 0 to List.Count-1 do
      begin
        if List.Strings[x] = 'Notification' then
        begin
          InitProtocol(Protocol);
          Protocol.Command     := CustomerNotification;
          Protocol.Sender.Notification := 'Custom Notification';
          ToSend                := ProtocolToBytes(Protocol);
          Con.Connection.IOHandler.Write(PTIdBytes(@ToSend)^);
          ClearBuffer(ToSend);
        end;
      end;

      Con.Unlock;
    end;
  finally
    List.Free;
  end;

  // Protocol

  AContext.Connection.IOHandler.ReadBytes(LBuffer, szProtocol, False);

  LProtocol := BytesToProtocol(PTBytes(@LBuffer)^);

  case LProtocol.Command of
    CustomerConnect: begin
     TLog.AddMsg('Connect');  
    end;

    CustomerDisconnect: begin
     TLog.AddMsg('Disconnect');  
    end;
  end;

  ClearBufferId(LBuffer);
  IndySleep(10);

And here is the TLog function:

constructor TLog.Create(const AMsg: String);
begin
  FMsg := AMsg;
  inherited Create;
end;

procedure TLog.DoSynchronize;
var
  LogName: String;
  ToFile: TextFile;
begin
  try
    LogName := ExtractFilePath(ParamStr(0))+'Logs\LogFile.txt';
    AssignFile(ToFile, LogName);

    if FileExists(LogName) then Append(ToFile) else ReWrite(ToFile);
    try
      WriteLn(ToFile, FMsg);
    finally
      CloseFile(ToFile);
    end;
  except
  end;

  Form1.Memo1.Lines.Add(FMsg);
end;

class procedure TLog.AddMsg(const AMsg: String);
begin
  with Create(AMsg) do
  try
    Synchronize;
  finally
    Free;
  end;
end;

I also use a IdSchedulerOfThreadPool1 instance on TIdTcpServer.

Any idea?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
PSDEVS
  • 57
  • 4
  • 1
    Blocking floods is a job for a firewall, not the server itself. `TIdTCPServer` has no flood control, other than its `MaxConnections` property, and its `OnConnect` event where you can disconnect clients that don't belong in the server. – Remy Lebeau Aug 19 '19 at 21:55
  • As for any stuck connections, what have you done so far to try to debug that yourself? I see a few places in your `OnExecute` code where blockages could occur: 1) not protecting `Con.(Un)Lock` with a `try..finally` block, 2) calling `ReadBytes()` without a timeout so pending notifications can still be sent while the client sits idle, and 3) using `TIdSync` instead of `TIdNotify` – Remy Lebeau Aug 19 '19 at 22:02
  • we already tried many firewalls, load balancer and others things. don't blocked the flood. we tested other socket solution using IOCP and don't have this kind of problem with flood, flooding or no clients still able to connect to server. – PSDEVS Aug 19 '19 at 22:19
  • You said about Try/Finally on Lock, it already have. only don't have at List check when add the command to queue. How i can add a timeout on ReadBytes? maybe is that and the IdNotify the problem os these stucks connections? – PSDEVS Aug 19 '19 at 22:21
  • Is this code who we use https://www.delphigeist.com/2010/09/custom-client-server-application-with.html – PSDEVS Aug 19 '19 at 22:32
  • 1
    "*You said about Try/Finally on Lock, it already have*" - no, you don't. If an exception is raised after `Con.Lock`, such as on `IOHandler.Write()`, you don't call `Con.Unlock()`. "*How i can add a timeout on ReadBytes?*" - use the `IOHandler.ReadTimeout` property. Though I would suggest using `IOHandler.CheckForDataOnSource()` before calling `IOHandler.ReadBytes()`. I've posted examples of sending unsolicited events from `TIdTCPServer` many times before in past questions, and other forums. – Remy Lebeau Aug 19 '19 at 23:21
  • "*we tested other socket solution using IOCP and don't have this kind of problem with flood*" - `TIdTCPServer` creates a separate worker thread per client. IOCP does not use a thread per client. A flood could still take down an IOCP server, but it won't be caused by starving thread resources, just socket resources. – Remy Lebeau Aug 19 '19 at 23:27
  • Here is a tool who can flood the tcpserver for you see better what i'm saying https://www.4shared.com/rar/FcLbS3W3/derrubador_-_wwwcidademuuni7ne.html?cau2=403tNull&ua=WINDOWS – PSDEVS Aug 20 '19 at 01:05
  • Any idea of how prevent that? – PSDEVS Aug 21 '19 at 01:39

0 Answers0