tags:

views:

399

answers:

4

We have an application which listens for incoming TCP requests using the Indy 10.1.1 components that ship with Delphi 2007.

Occassionally we receive incoming connections which are not from our client application. Typically, one of two things happens: 1) the connection is terminated by the client before any data is received, or 2) data is received which we're not expecting and we manually terminate the connection.

However, we've received connections where no data is received and appear to persist until the client terminates the connection from their end.

Is there a way to terminate such a connection from the server if no data is received after a specified amount of time?

A: 

You should be able to call (TIdTCPConnection).Disconnect.

François
+1  A: 

In your OnExecute event handler, keep track of when the last good data was received from the client. Using the connection's ReadTimeout property, you can timeout pending read operations periodically so you can check if the client has not sent data for awhile, and if so then disconnect it.

Remy Lebeau - TeamB
That's exactly what I was looking for. I knew the client had a ReadTimeout property, but I didn't realize the IOHandler of the connection did. Thanks.
A.J.
A: 

Save this as killthread.pas

unit killthread;

interface

uses
  Classes, IdTCPServer, IdTCPClient, IdContext, Types, SyncObjs;

type
  TKillThread = class(TThread)
  private
    FContext: TIdContext;
    FInterval: DWORD;
    FEvent: TEvent;
  protected
    procedure Execute; override;
  public
    constructor Create(AContext: TIdContext; AInterval: DWORD); overload;
    destructor Destroy; override;
    procedure Reset;
    procedure Stop;
  end;

implementation

{ TKillThread }

constructor TKillThread.Create(AContext: TIdContext; AInterval: DWORD);
begin
  FContext := AContext;
  FInterval := AInterval;
  FEvent := TEvent.Create(nil, False, False, '');
  inherited Create(False);
end;

destructor TKillThread.Destroy;
begin
  FEvent.Free;
  inherited Destroy;
end;

procedure TKillThread.Reset;
begin
  FEvent.SetEvent;
end;

procedure TKillThread.Stop;
begin
  Terminate;
  FEvent.SetEvent;
  WaitFor;
end;

procedure TKillThread.Execute;
begin
  while not Terminated do
  begin
    if FEvent.WaitFor(FInterval) = wrTimeout then
    begin
      FContext.Connection.Disconnect;
      Exit;
    end;
  end;
end;

end.

Then do this on the server side:

procedure TYourTCPServer.OnConnect(AContext: TIdContext);
begin
  AContext.Data := TKillThread.Create(AContext, 120000);
end;

procedure TYourTCPServer.OnDisconnect(AContext: TIdContext);
begin
  TKillThread(AContext.Data).Stop;
end;

procedure TYourTCPServer.OnExecute(AContext: TIdContext);
begin
  if AContext.Connection.Connected then
  begin
    TKillThread(AContext.Data).Reset;
    // your code here
  end;
end;
ioan
That's a bit overkill if the server has a lot of clients connected, since you are doubling the number of running threads and kernel objects used.
Remy Lebeau - TeamB
A: 

i have similiar problem, i used delphi7+Indy9.

and my solution: in TIdTCPServer event onConnect, i do like this

procedure Tf_main.ServerHostConnect(AThread: TIdPeerThread);
begin
  //code something

  //mean AThread will do Disconnected  if Client no activity ( send receive ) on interval...) 
  AThread.Connection.ReadTimeout := 300000;  //5 minutes..

  //code something
end;

maybe on Indy10 you can do similiar like that