Encapsulate TClientSocket connections in Multithreads [closed]

4

I have a variable X number of electronic equipment (Meteorological stations) in my local network, each equipment provides a ServerSocket connection with an IP and a specific port, I have an application developed in DELPHI XE5 that connects to all these equipments, my application knows what the IPs and ports of these devices are, since they are registered in the database, when I open my application, I dynamically create a [TClientSocket (Array)] connection for each of these devices, to which I later exchange a series of information, such as a conversation, I ask the temperature to all the equipment and they answer me, or I can ask the temperature for one of them, the humidity for another, the speed of the wind for another etc ... through internal OPERATIONS.

Today I make a FOR loop of all the connected equipment and from this I know what operation with the equipment my software is and then I make the conversation in a random way with each equipment, but this is slow, because as the number of equipment increases , increases the slowness of FOR. What I want to do is a Thread to delete FOR, I would like to know if this is possible. The onConnect, OnRead, etc ... events of my TClientScojet are assigned in the creation of the TClientSocket Array, so I end up having this wait for one to use, then the other and I can not attend all the equipments at the same time.

I would like to be able to use Thread for this and attend all the equipment at the same time, but I do not dominate the concept and use.

[UPDATED]

Link of the complete source, I did not post here because it goes through a thousand lines:

link

Today I use this class I created extended from TClientSocket:

type
  TTermoCenter = class(TClientSocket)
  private
    countSema: Thandle;
    access: TCriticalSection;
    ...
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Push(inObject: TPalavra; priority: Integer); virtual;
    function Pop(pResObject: pObject; timeout: Integer): Boolean;
  end;

Here is the constructor:

constructor TTermoCenter.Create(AOwner: TComponent);
var
  I: Integer;
begin
  inherited;
  access := TCriticalSection.Create;
  ...
end;

Here is the destructor:

destructor TTermoCenter.Destroy;
var
  I: Integer;
begin
  ...
  access.Free;
  closeHandle(countSema);
  inherited;
end;

variable declaration:

var
  termocenters: array of TTermoCenter;

When creating my Form, I define the size of my Array

SetLength(termocenters, dm.sqlTermocenter.RecordCount);

And I create my connections based on what's in the database:     var       SocketTmp: TTermoCenter;

  while not cds.Eof do
  begin
    SocketTmp := TTermoCenter.Create(nil);
    SocketTmp.name := 'cdsNome';
    SocketTmp.Port := 'cdsPorta';
    SocketTmp.ClientType := ctNonBlocking;
    SocketTmp.Host := 'cdsIP';
    // atribui eventos
    SocketTmp.OnRead := TCPRead;
    SocketTmp.OnConnect := TCPConnect;
    SocketTmp.OnDisconnect := TCPDisconnect;
    SocketTmp.OnError := TCPError;

    //Coloca no Array
    termocenters[I] := SocketTmp;
    try
      termocenters[I].Active := True;
      sleep(1000);
    except
      on E: Exception do
        frmMain.mmErros.Lines.Add(TimeToStr(now) + ' - ' + E.ClassName + ' CriaConexao : ' + E.Message);
        end;
      end;
    end;
  cds.Next;
end;
end;

This is a well-coded code of what I have today, I'd like some help to implement Threads.

    
asked by anonymous 14.10.2014 / 21:11

1 answer

3

I'll agree with @PageNotFound, that your question is too broad and waiting for a functional code.

I can give you a few steps to guide. Here is an example using Generics, Annonymous Methods, and an anonymous Thread feature:

The idea is to have a connection pool and have a method that creates a Worker thread for each connection to accomplish a specific task

interface

uses
  System.Generics.Collections, Datasnap.Win.SConnect;

type
  TPoolConexoes = class(TObjectList<TSocketConnection>)
  private
    procedure SeuMetodoQueUsaConexao(const aConexao: TSocketConnection);
  public
    function NewConnection: TSocketConnection;
    function ObterConexoesPorStatus(const aStatus: string): TPoolConexoes;

    procedure ExecutarSeuMetodoParaLista(const Conexoes: TPoolConexoes);
  end;

implementation

uses
  System.Classes;

{ TPoolConexoes }

procedure TPoolConexoes.ExecutarSeuMetodoParaLista(const Conexoes: TPoolConexoes);
var
  conexao: TSocketConnection;
  threadAtual: TThread;
begin
  for conexao in Conexoes do
  begin
    threadAtual := TThread.CreateAnonymousThread(
      procedure
      begin
        Self.SeuMetodoQueUsaConexao(conexao);
      end
    );
    threadAtual.FreeOnTerminate := True;
    threadAtual.Start;
  end;

end;

function TPoolConexoes.NewConnection: TSocketConnection;
var
  conexaoTemp: TSocketConnection;
begin
  conexaoTemp := TSocketConnection.Create(nil);
  Self.Add(conexaoTemp);
  Result := conexaoTemp;
end;

function TPoolConexoes.ObterConexoesPorStatus(const aStatus: string): TPoolConexoes;
begin
  //sua logica aqui
end;

procedure TPoolConexoes.SeuMetodoQueUsaConexao(const aConexao: TSocketConnection);
begin
  //usa a conexao para fazer algo
end;

end.

You can even put all threads created in a ThreadList and manage the end of them

Or you can extend the thread class to hold the execution code instead of using the anonymous ones and keep the threads in a pool that will be running OnDemand

It all depends on your needs

    
15.10.2014 / 16:33