RTC Forums
April 19, 2024, 05:35:04 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: Windows Services with TRtcTcpServer  (Read 4871 times)
giancarlo
RTC Expired
*
Posts: 7


« on: December 19, 2016, 08:41:24 PM »

Hello Danijel, please give your advice 

Huh

I recently bought the RTC SDK because I need to build a windows service to work on the following scenario:

There will be 50 devices sending a string of characters to a fixed IP address and a port, for example: 3-PAL, 12-02-16 14: 17: 46,5916386327, Camilo.
The 50 devices are sending 15,000 lines per day, from 3:00 am to 10:00 pm.

That string of characters I'm receiving using the TRtcTCPServer component, in the OnDataReceived event, everything is ok. The problem is that the service is not stable and at some point in the day, although the service manager window says that it is running, the information is not arriving to be recorded to the database.

I would like to know which is the best option to develop a service as described above, as I said I am using:

TRtcTcpServer with MultiThread = True
FireDac for connection and insert into the database.
Delphi XE6


I do not know if i'm doing the best, thanks in advanced and sorry for the long post

The code in the event OnExecute of the service, is as follow:

Code:
implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  vgad.Controller(CtrlCode);
end;

function Tvgad.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure Tvgad.ServiceExecute(Sender: TService);
begin

  Timer1.Enabled := True;

  DoConectarDBSistema;
  DoConectarDBDatos;
  qrSQL.Close;
  qrSQL.SQL.Text := 'SELECT IP_SERVER, PUERTO FROM PARAMETRO';
  qrSQL.Open();
  rtcServer.ServerAddr := qrSQL.FieldByName('IP_SERVER').AsString;
  rtcServer.ServerPort := qrSQL.FieldByName('PUERTO').AsString;

  rtcServer.Listen();

  while not Terminated do
  ServiceThread.ProcessRequests(True);
  Timer1.Enabled := False;

end;

procedure Tvgad.rtcServerDataReceived(Sender: TRtcConnection);
Var sDato: String;
  FF: Text;
  sFile: String;
begin

  Timer1.Enabled := False;
  sDato := Sender.Read;
  qrSQL.SQL.Text := ' insert into vw_linea ( ' +
                    '    linea)     ' +
                    '  values (     ' +
                    '    :linea)    ' ;
  qrSQL.ParamByName('linea').AsString := sDato;
  Try
    qrSQL.ExecSQL;
    Timer1.Enabled := True;
  Except
    on E: Exception do begin
      // Log the received string
      sFile := 'c:\GADIDX\LOG\LineasX.log';
      AssignFile(FF, 'c:\GADIDX\LOG\LineasX.log');
      if FileExists(sFile) then begin
        Append(FF);
      end else begin
        Rewrite(FF);
      end;
      Writeln(FF, sDato);
      CloseFile(FF);

      // Log the error exception
      sFile := 'c:\GADIDX\LOG\Errores.log';
      AssignFile(FF, 'c:\GADIDX\LOG\Errores.log');
      if FileExists(sFile) then begin
        Append(FF);
      end else begin
        Rewrite(FF);
      end;
      sDato := FormatDateTime('dd/mm/yyyy hh:mm:ss', Now) +
                ': ECN = ' + E.ClassName +
                '  ---  ' +
                ' EM = ' + E.Message;
      Writeln(FF, sDato);
      CloseFile(FF);


      Timer1.Enabled := True;
    end;
  End;
end;

procedure Tvgad.ServiceDestroy(Sender: TObject);
begin
  rtcServer.StopListen;
end;

procedure Tvgad.Timer1Timer(Sender: TObject);
var
  FF: Text;
  sFile: String;
begin
  sFile := 'c:\GADIDX\LOG\GadIdx.log';
  AssignFile(FF, 'c:\GADIDX\LOG\GadIdx.log');
  if FileExists(sFile) then begin
    Rewrite(FF);
  end else begin
    Rewrite(FF);
  end;
  Writeln(FF, FormatDateTime('dd/mm/yyyy hh:mm:ss', Now));
  CloseFile(FF);
end;

procedure Tvgad.DoConectarDBSistema;
begin
  //
  fdCia.Connected := False;
  with fdCia.Params do
  begin
    Clear;
    Add('DriverID=FB');
    Add('Database=' + 'C:\GADIDX\DATOS\SYSTEMS.WAS');
    Add('User_Name=SYSDBA');
    Add('Password=masterkey');
    Add('CharacterSet=UNICODE_FSS');
    Add('CreateDatabase=No');
    Add('ExtendedMetadata=True');
    Add('Server=' + '');
    Add('Protocol=' + 'LOCAL');
  end;
  fdCia.Open();
  cnDato.Close;

end;

procedure Tvgad.cnDatoAfterConnect(Sender: TObject);
begin
  qrSQL.SQL.Text := 'UPDATE PARAMETRO SET ULTIMA_FECHA_SERVIDOR = :FECHA';
  qrSQL.ParamByName('FECHA').AsDateTime := NOW;
  qrSQL.ExecSQL;
end;

procedure Tvgad.DoConectarDBDatos;
begin
  //
  // Vamos buscar la ruta de la base de datos de la primara compania
  qrCia.Close;
  qrCia.Open;
  //
  // Vamos asignar la ruta de la base de datos de la compania.
  cnDato.Connected := False;
  with cnDato.Params do
  begin
    Clear;
    Add('DriverID=FB');
    Add('Database='   + qrCia.FieldByName('RUTA_BASE_DATO').AsString);
    Add('User_Name=SYSDBA');
    Add('Password=masterkey');
    Add('Server='     + qrCia.FieldByName('SERVIDOR').AsString);
    Add('Protocol='   + qrCia.FieldByName('PROTOCOLO').AsString);
    Add('CreateDatabase=No');
    Add('ExtendedMetadata=True');
  end;
  cnDato.Open();
  qrCia.Close;
  fdCia.Close;
end;


end.
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #1 on: December 20, 2016, 10:11:01 AM »

1. If you use RTC Server components with MultiThreaded=TRUE, you have to make sure that all your code written inside RTC events  is thread-safe. But ... as far as I can tell from your example code, you are using a single set of database access components for your multi-threaded Server, which is a bomb just waiting to explode. Unless you are using components/objects which are designed to be accessed from multiple threads at the same time, you either have to (A) secure access to those components/objects - for example by using critical sections, or (B) dinamically create those components/objects before they are needed and destroy them afterwards, or (C) implement a thread-safe "component/object" pool, so you can re-use components/objects previously created but not currently in use in order to minimize the time "wasted" on creating/destroying components (and opening/closing database connections - when using database access components).

2. TCP/IP is a streaming protocol with no prefefined structure, which means that your data will NOT be sent in "lines", but as a continuous stream split into smaller and larger packages, depending on the API and the network in use. I don't know if your example is just a simple test with a goal to store raw TCP/IP packages in a database, but I don't see anything in your code that would indicate any kind of data processing to extract your "lines" from the raw data stream which is received as packages in the OnDataReceived event.

By the way ... why are you using raw TCP/IP instead of HTTP?

Best Regards,
Danijel Tkalcec
Logged
giancarlo
RTC Expired
*
Posts: 7


« Reply #2 on: December 20, 2016, 09:13:35 PM »

Hi Danijel

Thank you very much for your quick response.!!!

1. I will try to do the B option, as it is the easiest for me, although I understand that option C is the best, but for lack of time I will do the B for now.

2. Well Danijel, here in the code you do not see data process is because I am only inserting the string receiving to a table in the database then the table trigger do the data processing.

I'm using TCP/IP just because I'm not an expert in this field, but please if you give me your advice I would appreciate it. My case is that i have 50 device (Hardware), sending a simple line like this (3-PAL, 12-02-16 14: 17: 46,5916386327, Camilo) each minute approximately concurrently. I thought that using TCP/IP would be the best option, but now I do not know if it is so, since you ask me why I do not use HTTP, which RTC component I recommend?.

Thanks for your support

Giancarlo



Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #3 on: December 21, 2016, 09:15:44 AM »

If you have to build a Server for Clients that already use a custom protocol based on TCP/IP, you have no choice but to use the TRtcTcpServer component and manually implement data processing based on your Clients protocol specification.

But ... if you were building a Server for Clients using a protocol based on HTTP, or ... if you were also building the Client side, then you can choose HTTP - which provides the envelope for a lot of standards, works seamlessly through firewalls and HTTP Proxies and is much easier to use with RTC, since HTTP processing is already built into all higher-level RTC components.

Best Regards,
Danijel Tkalcec
Logged
giancarlo
RTC Expired
*
Posts: 7


« Reply #4 on: January 03, 2017, 02:01:17 PM »

Hi, Happy new year Members!!!

Danijel thanks for your help and for your product, every thing is running ok, and very easy!!!!

Gian

Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #5 on: January 03, 2017, 02:15:17 PM »

Happy New Year to you too and thank you for your feedback.

Best Regards,
Danijel Tkalcec
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.024 seconds with 16 queries.