Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Jul : IdTelnet (Indy 10): Multi - Telnet sessions.

www.cryer.info
Managed Newsgroup Archive

IdTelnet (Indy 10): Multi - Telnet sessions.

Subject:IdTelnet (Indy 10): Multi - Telnet sessions.
Posted by:"jimmydorsey" (jimmydors..@yahwho.com)
Date:31 Jul 2006 15:50:26

Delphi 6 and indy 10.1.5 Indy Components/10.0.52 source
I am posting this on Borland now - not Google...  (Ugghhhh - now it'll be on google twice...)


I am trying to create an application that connects(telnet) to
multiple(8 to 20+) unix boxes and executes a list of several commands.  (I will simplify the commands to buttons.)

The list of servers is loaded via an INI file.  A TListbox and TIdTelnet are placed on a frame and are created dynamically on a TTabSheet(in a TPageControl) base on the number of entries in the INI file.

So far it seems to work for about 3 or less connections.  On the fourth and more, I start getting hangs.  The application becomes unresponsive.  Occasionally it returns - only to become unresponsive again.

I am alittle unsure as to which way to go now.

I suspect my design is at fault, but it could simply be my
implementation.  Am I being unrealistic?  I am thinking that this
should be accomplishable for the magnitude(20-25) that I am looking at.

I haven't created threads for each dynamic tab - I assume some
threading is done in the component, but not sure exactly how that
playes into it.  Do I need to create my own threads for each?

I'll post code so as to skip that request  ;-)  Thanks in advance for any help.  Any streamlining/improvements on the component searching would be nice also.  It is 380 lines or so including Francois Piette's demo code for the DataAvailable.  I use long lines to(well past 80 sometimes) - sorry.

More info:

I tried changing this connecting to each in a serial manner and the same hang occurs.  The fourth connection hangs in the
HandleIncomingData procedure of the IdTelnet component.

I rearranged my servers to ensure it wasn't one specific server giving me issues.  I am not expecting any more data, so I can't determine why it is hanging.

More testing indicates actually that 5 connections are good and 7
connections are good, but even numbered connections over 2 are bad (4, 6, or 8).  Weird.  Still hanging in the HandleIncomingData procedure.

More testing...


unit fOctopus;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Menus, StdCtrls, ComCtrls, ToolWin, IniFiles, Dialogs, ImgList,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdTelnet,
  fTelnet, ExtCtrls;

//******************************************************************************
type
  TSite = record
    site      : string;
    visn      : string;
    moniker   : string;
    id        : string;
    server    : string;
    port      : integer;
    FContinue : boolean;
    FNext     : boolean;
    FConnected: boolean;
  end;
//******************************************************************************
  TfrmOctopus = class(TForm)
    MainMenu1: TMainMenu;
    statusBar: TStatusBar;
    File1: TMenuItem;
    Connection1: TMenuItem;
    Help1: TMenuItem;
    ToolBar1: TToolBar;
    tbtnConnect: TToolButton;
    tbtnButton1: TToolButton;
    tbtnUpCarat: TToolButton;
    ToolButton4: TToolButton;
    tbtnKIDS: TToolButton;
    ToolButton6: TToolButton;
    ToolButton7: TToolButton;
    imagesEnabled: TImageList;
    imagesDisabled: TImageList;
    tabPage: TPageControl;
    pnlLeft: TPanel;
    listboxSites: TListBox;
    pnlAccessVerify: TPanel;
    lblAccess: TLabel;
    lblVerify: TLabel;
    editAccess: TEdit;
    editVerify: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Connect(i, j: integer);
    procedure Disconnect(Sender: TObject);
//------------------------------------------------
    procedure telnetClientDataAvailable(Sender: TIdTelnet; const Buffer: String);
    procedure telnetClientStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: String);
    procedure tbtnUpCaratClick(Sender: TObject);
    procedure tbtnConnectClick(Sender: TObject);
    procedure tbtnKIDSClick(Sender: TObject);
    procedure listboxSitesDrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
//------------------------------------------------
  private
    { Private declarations }
    FOctopusINI: TIniFile;
    FSites: array of TSite;
    FslSitelist: TStringlist;

    FCursor: TCursor;

    FStageConnect: boolean;
  public
    { Public declarations }
    procedure ImportINI;
    procedure SetSites(i: integer);

    procedure UpdateScreen(listboxToSendTo: TListbox);
    procedure SendCommand(S: string; telnetToSendTo: TIdTelnet);

    procedure KIDS;
  end;
//******************************************************************************
var
  frmOctopus: TfrmOctopus;

implementation

{$R *.dfm}

//******************************************************************************
procedure TfrmOctopus.ImportINI;
var
  iniSectionName: string;
  i: integer;
begin
  listboxSites.Items.Clear;
  FOctopusINI := TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'Octopus.ini');
  with FOctopusINI do
  begin
    FslSitelist := TStringlist.Create;
    FslSitelist.Clear;
    FOctopusINI.ReadSection('Sites', FslSitelist);
    if (FslSitelist.Count > 0) then
    begin
      SetLength(FSites, FslSitelist.Count);
      for i := 0 to (FslSitelist.Count - 1) do
      begin
        iniSectionName := FOctopusINI.ReadString('Sites', 'site' + IntToStr(Ord(i)), '');
        with FSites[i] do
        begin
          site       := FOctopusINI.ReadString(iniSectionName,  'site',    '');
          visn       := FOctopusINI.ReadString(iniSectionName,  'visn',    '');
          moniker    := FOctopusINI.ReadString(iniSectionName,  'moniker', '');
          id         := FOctopusINI.ReadString(iniSectionName,  'id',      '');
          server     := FOctopusINI.ReadString(iniSectionName,  'server',  '');
          port       := FOctopusINI.ReadInteger(iniSectionName, 'port',     0);
          FContinue  := TRUE;
          FNext      := FALSE;
          FConnected := FALSE;
        end;
        listboxSites.Items.Add(FSites[i].site);
      end;
    end;
  end;
end;
//******************************************************************************
procedure TfrmOctopus.SetSites(i: integer);
var
  tabClients: TTabSheet;
  frameClients: TframeClient;
begin
  tabClients := TTabSheet.Create(tabPage);
  tabClients.PageControl := tabPage;
  tabClients.Caption := FSites[i].moniker;
  tabClients.Tag := i;

  frameClients := TframeClient.Create(tabClients);
  frameClients.Parent := tabClients;
  frameClients.Align := alClient;

  frameClients.telnetClient.Host := FSites[i].server;
  frameClients.telnetClient.OnStatus := telnetClientStatus;
  frameClients.telnetClient.OnDataAvailable := telnetClientDataAvailable;
end;
//******************************************************************************
procedure TfrmOctopus.FormCreate(Sender: TObject);
var
  i: integer;
begin
  ImportINI;
  for i := 0 to FslSiteList.Count - 1 do SetSites(i);
end;
//******************************************************************************
procedure TfrmOctopus.SendCommand(S: string; telnetToSendTo: TIdTelnet);
var
  i: integer;
begin
  for i := 1 to length(S) do telnetToSendTo.SendCh(S[i]);
  telnetToSendTo.SendCh(#13);
end;
//******************************************************************************
procedure TfrmOctopus.Connect(i, j: integer);
var
  s: string;
  l: integer;
begin
(*
  for i := 0 to tabPage.PageCount - 1 do
  begin
    for j := 0 to tabPage.Pages[i].ControlCount - 1 do
*)
      if not((tabPage.Pages[i].Controls[j] as TframeClient).telnetClient.Connected) then
      begin
        (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient.Connect;
        l := tabPage.Pages[i].Tag;
        tabPage.Pages[i].Tag := (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient.TelnetThread.ThreadID;
        s := UPPERCASE(FSites[l].moniker) + 'VISTA';
        SendCommand(s, (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient);
      end;
(*
  end;
*)
end;
//******************************************************************************
procedure TfrmOctopus.Disconnect(Sender: TObject);
var
  i, j: integer;
begin
  for i := 0 to tabPage.PageCount - 1 do
  begin
    for j := 0 to tabPage.Pages[i].ControlCount - 1 do
      if ((tabPage.Pages[i].Controls[j] as TframeClient).telnetClient.Connected) then
      begin
        (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient.Disconnect;
      end;
  end;
end;
//******************************************************************************
procedure TfrmOctopus.FormDestroy(Sender: TObject);
var
  i, j: integer;
begin
  for i := 0 to tabPage.PageCount - 1 do
  begin
    for j := 0 to tabPage.Pages[i].ControlCount - 1 do
      if not((tabPage.Pages[i].Controls[j] as TframeClient).telnetClient.Connected) then
      begin
        if ((tabPage.Pages[i].Controls[j] as TframeClient).telnetClient.Connected) then
          (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient.Disconnect;
      end;
  end;
  FslSitelist.Free;
  FOctopusINI.Free;
end;
//******************************************************************************
procedure TfrmOctopus.UpdateScreen(listboxToSendTo: TListbox);
begin
  if (listboxToSendTo.Items.Count > 0) then
    listboxToSendTo.TopIndex := listboxToSendTo.Items.Count - 1;
//  Application.ProcessMessages;
end;
//******************************************************************************
procedure TfrmOctopus.telnetClientDataAvailable(Sender: TIdTelnet; const Buffer: String);
const
    CR = #13;
    LF = #10;
var
    Start, Stop, iCurrentPID, i, j: Integer;
begin
  iCurrentPID := Sender.TelnetThread.ThreadID;
  for i := 0 to tabPage.PageCount - 1 do
  begin
    if tabPage.Pages[i].Tag = iCurrentPID then  //  Sync tab
    begin
      for j := 0 to tabPage.Pages[i].ControlCount - 1 do
      begin                                     //  Find frame (only control, but for later...)
//------------------------------------------------
{This routine comes directly from the ICS TNDEMO code. Thanks to Francois Piette
It updates the memo control when we get data}
        if ((tabPage.Pages[i].Controls[j] as TframeClient).listboxClient.Items.Count = 0) then
          (tabPage.Pages[i].Controls[j] as TframeClient).listboxClient.Items.Add('');

        Start := 1;
        Stop  := Pos(CR, Buffer);
        if Stop = 0 then Stop := Length(Buffer) + 1;
        while Start <= Length(Buffer) do
        begin
            (tabPage.Pages[i].Controls[j] as TframeClient).listboxClient.Items.Strings[(tabPage.Pages[i].Controls[j] as TframeClient).listboxClient.Items.Count - 1] :=
                (tabPage.Pages[i].Controls[j] as TframeClient).listboxClient.Items.Strings[(tabPage.Pages[i].Controls[j] as TframeClient).listboxClient.Items.Count - 1] +
                Copy(Buffer, Start, Stop - Start);
            if Buffer[Stop] = CR then
            begin
                (tabPage.Pages[i].Controls[j] as TframeClient).listboxClient.Items.Add('');
                {$IFNDEF Linux}
                SendMessage((tabPage.Pages[i].Controls[j] as TframeClient).listboxClient.Handle, WM_KEYDOWN, VK_UP, 1);
                {$ENDIF}
            end;
            Start := Stop + 1;
            if Start > Length(Buffer) then Break;
            if Buffer[Start] = LF then Start := Start + 1;
            Stop := Start;
            while (Buffer[Stop] <> CR) and (Stop <= Length(Buffer)) do Stop := Stop + 1;
        end;
//-------------------------------------------------------
        if FStageConnect then
        begin  //  Access & Verify codes
          if (pos('ACCESS CODE:', Buffer) > 0) and FSites[i].FContinue then
            SendCommand(editAccess.Text + #9 + editVerify.Text, (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient);
          if pos('Not a valid ACCESS CODE/VERIFY CODE pair.', Buffer) > 0 then
          begin  //  Signed on?
            FSites[i].FContinue := FALSE;
            listboxSites.Items[listboxSites.Items.IndexOf(FSites[i].site)] := '-' + FSites[i].site;
            FSites[i].FConnected := FALSE;
            if (i < tabPage.PageCount - 1) then Connect(i + 1, 0);  //  Connect singly.
            if (i = tabPage.PageCount - 1) then Screen.Cursor := FCursor;
            FSites[i].FNext := TRUE;
          end;
          if pos('You last signed on', Buffer) > 0 then
          begin  //  Signed on?
            FSites[i].FNext := TRUE;
            listboxSites.Items[listboxSites.Items.IndexOf(FSites[i].site)] := '+' + FSites[i].site;
            FSites[i].FConnected := TRUE;
            if (i < tabPage.PageCount - 1) then Connect(i + 1, 0);  //  Connect singly.
            if (i = tabPage.PageCount - 1) then Screen.Cursor := FCursor;
          end;
          UpdateScreen((tabPage.Pages[i].Controls[j] as TframeClient).listboxClient);
        end;
//-------------------------------------------------------
      end;
    end;
  end;
end;
//******************************************************************************
procedure TfrmOctopus.telnetClientStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: String);
begin
//  Showmessage(AStatusText);

//  Showmessage(ASender.ClassName);    //TIdtelnet
//  statusBar.Panels[0].Text := statusBar.Panels[0].Text + 'BOI' + '+    ';
//  (ASender as TIdTelnet).TelnetThread.ThreadID
  {SetStatus Bar}
end;
//******************************************************************************
procedure TfrmOctopus.tbtnUpCaratClick(Sender: TObject);
var
  i, j:integer;
begin
  for i := 0 to tabPage.PageCount - 1 do
  begin
    for j := 0 to tabPage.Pages[i].ControlCount - 1 do
      SendCommand('^' + #13, (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient);
  end;
end;
//******************************************************************************
procedure TfrmOctopus.tbtnConnectClick(Sender: TObject);
begin
  FStageConnect := TRUE;
  FCursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;
  Connect(0, 0);
end;
//******************************************************************************
procedure TfrmOctopus.tbtnKIDSClick(Sender: TObject);
begin
  FStageConnect := FALSE;
  KIDS;
end;
//******************************************************************************
procedure TfrmOctopus.KIDS;
var
  s: string;
  i, j: integer;
begin
  for i := 0 to tabPage.PageCount - 1 do
  begin
    for j := 0 to tabPage.Pages[i].ControlCount - 1 do
      if FSites[i].FConnected then
      begin
        SendCommand('Programmer Options', (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient);
        SendCommand('KIDS', (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient);
        SendCommand('Installation', (tabPage.Pages[i].Controls[j] as TframeClient).telnetClient);
      end;
  end;
end;
//******************************************************************************
procedure TfrmOctopus.listboxSitesDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
begin
  try
    with (Control as TListBox).Canvas do  { draw on control canvas, not on the form }
    begin
      FillRect(Rect);       { clear the rectangle }
      if odSelected in State then
        Font.Color := clWhite
      else
      begin
        if (pos('+', listboxSites.Items[Index]) > 0) then Font.Color := clGreen
        else if (pos('-', listboxSites.Items[Index]) > 0) then Font.Color := clMaroon
        else Font.Color := clBlack;
      end;
      TextOut(Rect.Left + 2, Rect.Top, (Control as TListBox).Items[Index]);  { display the text }
    end;
  except
    MessageDlg('Access Violation Error Trap: On Draw.', mtError, [mbOK],0);
    Application.Terminate;
  end;
end;
//******************************************************************************

end.

Replies:

www.cryer.info
Managed Newsgroup Archive