有时,IdTcpServer不会在Disconnect事件中检索信息

时间:2019-10-20 20:12:10

标签: delphi

我不知道为什么,但是有时在日志中发生断开连接事件时,他不检索ip和主机名,也许是因为在检索信息之前已经断开连接了吗?如果是的话,如何解决?

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
var
  DadosConexao : TClient;
begin
  DadosConexao := TClient(AContext);

  DadosConexao.PeerIP      := AContext.Connection.Socket.Binding.PeerIP;
  DadosConexao.HostName    := GStack.HostByAddress(DadosConexao.PeerIP);
  DadosConexao.Connected   := Now;
  DadosConexao.LastAction  := DadosConexao.Connected;

  TThread.Queue(nil,
  procedure
  begin
    Memo2.Lines.Add(Format('[%s][%s] connect', [TimeToStr(Now), DadosConexao.PeerIP, DadosConexao.HostName]));
  end);

  RefreshListBox;
end;

procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
var
  DadosConexao : TClient;
begin
  DadosConexao := TClient(AContext);

  TThread.Queue(nil,
  procedure
  begin
    Memo2.Lines.Add(Format('[%s][%s] disconnect', [TimeToStr(Now), DadosConexao.PeerIP, DadosConexao.HostName]));
  end);

  RefreshListBox;
end;

示例,在这里获取信息:

[17:12:38] [192.168.15.3]连接

[17:12:38] [192.168.15.3]断开连接

这里没有:

[17:12:38] [192.168.15.3]连接

[17:12:38] []断开

1 个答案:

答案 0 :(得分:1)

TThread.Queue()是异步的,它不会阻塞调用线程。它将指定的方法/过程排队,然后立即退出。 UI主线程检查队列中是否有方法/过程,以便尽早运行。因此,TIdContext对象很可能在匿名过程实际在主UI线程中运行之前就被销毁了。

您需要更改日志记录代码,以使匿名过程捕获单个字符串值,而不是捕获TClient对象本身,例如:

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
var
  DadosConexao : TClient;
  PeerIP, HostName: string;
begin
  DadosConexao := TClient(AContext);

  DadosConexao.PeerIP := AContext.Connection.Socket.Binding.PeerIP;
  DadosConexao.HostName := GStack.HostByAddress(DadosConexao.PeerIP);
  DadosConexao.Connected := Now;
  DadosConexao.LastAction := DadosConexao.Connected;

  PeerIP := DadosConexao.PeerIP;
  HostName := DadosConexao.HostName;

  TThread.Queue(nil,
    procedure
    begin
      Memo2.Lines.Add(Format('[%s][%s][%s] connect', [TimeToStr(Now), PeerIP, HostName]));
    end
  );

  RefreshListBox;
end;

procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
var
  DadosConexao : TClient;
  PeerIP, HostName: string;
begin
  DadosConexao := TClient(AContext);

  PeerIP := DadosConexao.PeerIP;
  HostName := DadosConexao.HostName;

  TThread.Queue(nil,
    procedure
    begin
      Memo2.Lines.Add(Format('[%s][%s][%s] disconnect', [TimeToStr(Now), PeerIP, HostName]));
    end
  );

  RefreshListBox;
end;

然后可以通过将日志记录代码包装到其自己的过程中来进一步采取行动:

procedure TForm1.ClientStateUpdated(Client: TClient; Connected: Boolean);
var
  PeerIP, HostName: string;
begin
  PeerIP := Client.PeerIP;
  HostName := Client.HostName;

  TThread.Queue(nil,
    procedure
    begin
      Memo2.Lines.Add(Format('[%s][%s][%s] %s', [TimeToStr(Now), PeerIP, HostName, iif(Connected, 'connect', 'disconnect')]));
    end
  );

  RefreshListBox;
end;

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
var
  DadosConexao : TClient;
  PeerIP, HostName: string;
begin
  DadosConexao := TClient(AContext);

  DadosConexao.PeerIP := AContext.Connection.Socket.Binding.PeerIP;
  DadosConexao.HostName := GStack.HostByAddress(DadosConexao.PeerIP);
  DadosConexao.Connected := Now;
  DadosConexao.LastAction := DadosConexao.Connected;

  ClientStateUpdated(DadosConexao, true);
end;

procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
begin
  ClientStateUpdated(TClient(AContext), false);
end;