These are chat archives for IndySockets/Indy

29th
Jun 2017
elekgeek
@elekgeek
Jun 29 2017 22:53

@rlebeau this has worked for me and solved my problem:

     with IdTCPServer1.Contexts.LockList do
        try
           for iA := Count - 1 downto 0 do
           begin
              Context := Items[iA];
              if Context = nil then
                 Continue;
              Context.Connection.IOHandler.WriteBufferClear;
              Context.Connection.IOHandler.InputBuffer.Clear;
              Context.Connection.IOHandler.Close;
              if Context.Connection.Connected then
                 Context.Connection.Disconnect;
           end;
        finally
           IdTCPServer1.Contexts.UnlockList;
           IdTCPServer1.Active := False;
        end;

What do you think?

This code also suggested by you works very well:

  with AContext.Connection.IOHandler do
  begin
    CheckForDataOnSource(10);
    CheckForDisconnect; // <-- add this
    if not InputBufferIsEmpty then
    begin
      RxBufStr := InputBufferAsString(IndyTextEncoding_8Bit); // <-- don't assume any encoding
      Log(RxBufStr);
      Write(RxBufStr, IndyTextEncoding_8Bit); // <-- use TIdIOHandler.Write() instead
    end;
  end;

Now my question:

  • why were you not been able to suggest such a solution, no offense intended, but for sure you have a good reason.
  • How can the client check if the server went down and close its own connection?
Remy Lebeau
@rlebeau
Jun 29 2017 22:57
@elekgeek you don't need any of that. Just set Active to false, it already disconnects the clients for you, and then waits for their threads to terminate. Your issue is that your code is blocking the threads from terminating correctly. That is what you need to fix properly, not hack around it.
elekgeek
@elekgeek
Jun 29 2017 22:59

Look again please, I edited my previous answer

man my code is very simple, Look at my last answer, I am not blocking anything

and BTW
procedure TForm2.Log(const s: string);
begin
  mLog.Lines.Add(s);
end;
elekgeek
@elekgeek
Jun 29 2017 23:20
@rlebeau Just set Active to false, it already disconnects the clients for you apparently it is not shutting down any threads.. my code is very simple and you have already seen it..
Remy Lebeau
@rlebeau
Jun 29 2017 23:23

@elekgeek your Log() function is directly accessing a UI component (a TMemo?). THAT IS NOT THREAD-SAFE! That could easily cause deadlocks (amongst many other problems). OnExecute is fired in a worker thread, so Log() MUST synchronize with the main UI thread. I suggest it use TThread.Queue() or TIdNotify for that purpose (depending on your version of Delphi). That would avoid any cross-thread access issues, avoid any deadlock scenarios, and avoid blocking the OnExecute code (which should not need to wait on the UI to display log messages). For example:

procedure TForm2.Log(const s: string);
begin
  TThread.Queue(nil,
    procedure
    begin
      mLog.Lines.Add(s);
    end
  );
end;

or:

uses
  ..., IdSync;

type
  TLog = class(TIdNotify)
  protected
    FMsg: string;
    procedure DoNotify; override;
  public
    constructor Create(const s: string); reintroduce;
  end;

constructor TLog.Create(const s: string);
begin
  inherited Create;
  FMsg := s;
end;

procedure TLog.DoNotify;
begin
  Form2.mLog.Lines.Add(FMsg);
end;

procedure TForm2.Log(const s: string);
begin
  TLog.Create(s).Notify;
end;