Club Delphi  
    Paypal   FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Internet
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Colaboración Paypal con ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 16-07-2010
manuc manuc is offline
Miembro
 
Registrado: abr 2010
Posts: 165
Poder: 17
manuc Va por buen camino
Hola richy08,

En algún proyecto he realizado lo mismo que quieres hacer, es decir, un servidor multihilo que genera una batería de conexiones (una por hilo) de tan forma que cada hilo pueda ejecutar una serie de sentencias sql directa y simultaneamente.

Puede funcionar perfectamente.

Al leer lo que comentas, me surge una duda.
Entiendo que lo que estás programando es un servidor TCP y que al recibir una conexión entrante (de un cliente) se atiende por un hilo en el servidor.

¿Por qué quieres generar una conexión por hilo en TCPServer?
¿para ganar mayor velocidad en la ejecución de sentencias?
¿agilizar la concurrencia en el servidor?

Te lo comento porque también puedes crear un procedimiento en el TCPServer que se encargue de la conexión y de las sentencias SQL y llamarlo con el método synchronize del hilo.

Básicamente esto lo que hace es acceder de modo controlado a la VCL y así evitas los problemas de acceso a componentes, por parte de lo hilos.

Un saludo.
Responder Con Cita
  #2  
Antiguo 16-07-2010
Avatar de richy08
richy08 richy08 is offline
Miembro
 
Registrado: may 2007
Ubicación: Bucerias, Nayarit Mexico
Posts: 529
Poder: 20
richy08 Va por buen camino
Cita:
Empezado por manuc Ver Mensaje
Hola richy08,
En algún proyecto he realizado lo mismo que quieres hacer, es decir, un servidor multihilo que genera una batería de conexiones (una por hilo) de tan forma que cada hilo pueda ejecutar una serie de sentencias sql directa y simultaneamente.

Puede funcionar perfectamente.

Al leer lo que comentas, me surge una duda.
Entiendo que lo que estás programando es un servidor TCP y que al recibir una conexión entrante (de un cliente) se atiende por un hilo en el servidor.

¿Por qué quieres generar una conexión por hilo en TCPServer?
¿para ganar mayor velocidad en la ejecución de sentencias?
¿agilizar la concurrencia en el servidor?

Te lo comento porque también puedes crear un procedimiento en el TCPServer que se encargue de la conexión y de las sentencias SQL y llamarlo con el método synchronize del hilo.

Básicamente esto lo que hace es acceder de modo controlado a la VCL y así evitas los problemas de acceso a componentes, por parte de lo hilos.

Un saludo.
hola manuc gracias por tu respuesta, bueno la idea de crear una conexion
por hilo es por que lo que he estando leyendo y comentarios de los compañeros que los querys no son hilo seguro es por esa la razon, creo que es esa la forma en que lo hice pero valla lo he estado testeando y al parecer funciona pero he tenido erorres de memoria en mi maqina por lo cual no estoy tan seguro de que tambien programado este , estos son los fragmnetos de codigo donde ejecuto las peticiones, te agradeceria si me pudieras orientar y en le caso de que vieras errores de logica me lo hicieras saber mil gracias por tu tiempo

//cliente
Código Delphi [-]

procedure TClientHandleThread.Execute;
begin
  while not Terminated do
  begin
    if not Frm_Posgue.Client.Connected then
      Terminate
    else
    try
      Frm_Posgue.Client.ReadBuffer(CB, SizeOf (CB));
      Synchronize(HandleInput);
    except
    end;
  end;
end;



 CBClientActive.Checked:=true;

    //datos de la reserva
    Qry_Busaco.close;
    Qry_Busaco.Parameters.ParamByName('nconf').Value:=Qry_principal.fieldbyname('nconf').Value;
    Qry_Busaco.Open;

    //trae le nombre
    Qry_Nombre.close;
    Qry_Nombre.Parameters.ParamByName('aowner').Value:=Qry_principal.fieldbyname('aowner').Value;
    Qry_Nombre.Open;

    CommBlock.Command      := '';//EditCommand.Text;         // assign the data
    CommBlock.MyUserName   := 'DESARROLLO';//Client.LocalName;
    CommBlock.Msg          := '';//EditMessage.Text;
    CommBlock.ReceiverName := '';//EditRecipient.Text;
    CommBlock.nconf        := Qry_principal.fieldbyname('nconf').Value;
    CommBlock.acode        := Qry_Busaco.fieldbyname('acode').value;
    CommBlock.nombre       := Qry_Nombre.fieldbyname('guest').Value;
    CommBlock.estado       :=1;

    Client.WriteBuffer (CommBlock, SizeOf (CommBlock), true);


//server

Código Delphi [-]
function TFrm_Interfaces.CreaAdo(Myusername, nombre: string; acode, estado : integer):boolean;
var
   i, seleccion :integer;
begin
       //coneccion mysql
       zConnect1:= TzConnection.Create(nil);
       With zConnect1 do
       begin
        Parent:= Frm_Interfaces;
        Name:= Myusername+'z';
        Catalog:= 'lookup';
        Database:= 'cdr';
        HostName:= '192.168.10.3';
        Password:= 'siti270';
        Protocol:= 'mysql-5';
        port:= 3306;
        User:= 'root';
        Connect;
       end;

       //coneccion mssql
       connect:= tadoconnection.Create(nil);
       With Connect do
       begin
        connectionstring:=cadena;
        loginprompt:=false;
        provider:='SQLOLEDB.1';
        name:=Myusername+'m';
        connected;
       end;

       //crea el query   mssql   busca extensiones
       Query      :=   TAdoquery.Create(nil);
       with Query  do
       begin
         Name :=   Myusername+'1';
         close;
         Connection:= connect;
         SQL.text:='select idext, DesTel from pbx_ext where acode=:acode ';
         parameters.ParamByName('acode').Value:=acode;
         Parent:= Frm_Interfaces;
         CursorType := ctStatic;
         open;
       end;

       //crea el query   mysql
       zQuery      :=   TzQuery.Create(nil);
       with zQuery  do
       begin
         Name :=   Myusername+'2';
         Connection:= zConnect1;
         SQL.text:='update lookup set  allowcalls=:allowcalls, ldesc=:ldesc where code=:code ';
         Parent:= Frm_Interfaces;
       end;

       i:=0;
       seleccion:=Query.RecordCount;
       Query.First;
       While ido
       begin
            zQuery.Close;
            zQuery.ParamByName('allowcalls').Value:=estado;
            zQuery.ParamByName('ldesc').Value:=nombre;
            zQuery.ParamByName('code').Value:=Query.fieldbyname('idext').Value;
            zQuery.ExecSQL;
            i:=i+1;
            Query.Next;
       end;
end;

procedure TFrm_Interfaces.ServerExecute(AThread: TIdPeerThread);
var
  ActClient, RecClient: PClient;                                                                              
  CommBlock, NewCommBlock: TCommBlock;
  RecThread: TIdPeerThread;
  i: Integer;
begin
  if not AThread.Terminated and AThread.Connection.Connected then
  begin
    AThread.Connection.ReadBuffer (CommBlock, SizeOf (CommBlock));
    ActClient := PClient(AThread.Data);
    ActClient.LastAction := Now;  // update the time of last action

    CreaAdo(CommBlock.MyUserName, CommBlock.nombre, CommBlock.acode, CommBlock.estado);

    Protocol.Lines.Add (TimeToStr(Time)+'The process for '+CommBlock.MyUserName+' was started');
    NewCommBlock.Command := 'DIALOG';       // the message should popup on the client's screen
    NewCommBlock.MyUserName := '[PBX Server]';  // the server's username
    NewCommBlock.Msg := 'The process was done  ';  // the message to show
    NewCommBlock.ReceiverName := '[return-to-sender]'; // unnecessary
                                                                                                                                           
    AThread.Connection.WriteBuffer (NewCommBlock, SizeOf (NewCommBlock), true);  // and there it goes...
  end;
end;
Responder Con Cita
  #3  
Antiguo 17-07-2010
manuc manuc is offline
Miembro
 
Registrado: abr 2010
Posts: 165
Poder: 17
manuc Va por buen camino
Hola richy08,

A simple vista, creo, que los errores de memoria te vienen dado porque no estás destruyendo los querys que creas.

Prueba a destruirlos cuando ya no los necesites.

Un saludo.
Responder Con Cita
  #4  
Antiguo 17-07-2010
Avatar de richy08
richy08 richy08 is offline
Miembro
 
Registrado: may 2007
Ubicación: Bucerias, Nayarit Mexico
Posts: 529
Poder: 20
richy08 Va por buen camino
gracias manuc la razon por lo que no los destruyo es por que no se con certeza si el hilo espera a que termine una peticion para empezar a ejecutar la otra, o si crea diferentes instancias de la funcion donde los crea me podrias iluminar saludos.
Responder Con Cita
  #5  
Antiguo 19-07-2010
manuc manuc is offline
Miembro
 
Registrado: abr 2010
Posts: 165
Poder: 17
manuc Va por buen camino
Hola richy08,

Dentro de cada hilo, la ejecución es lineal. Es decir, cuando se conecta el tcpClient, el tcpServer Crear un hilo que atenderá la actividad de esa conexión y la ejecución del código programado para ese hilo se hará de forma lineal.
Si, mientras un hilo ejecuta su código, entra otra conexión, se generará un hilo paralelo y se ejecutaran ambos al mismo tiempo.

Gracias a esto, el TCPServer es multihilo y cada conexión se ejecuta de forma independiente, salvo en los puntos donde se utilice "synchronize".

Sabiendo esto, puedes hacer dos cosas:

1.- Crear tus componentes en el evento onConnect del tcpServer. Es decir, por cada hilo que se crea en el tcpServer, creas los componentes correspondientes.
Para este caso, deberías destruir los componentes cuando no los necesites, es decir, cuando se destruye el hilo. Esto ocurre en el evento onDisconnect del tcpServer.

2.- Crear tus componentes en el evento onExecute del tcpServer. Es decir, cada vez que un hilo tiene actividad, creas los componentes que necesites.
Igualmente, cuando ya no necesites estos componentes, los debes destruir. Esto es justo al final del evento onExecute del tcpServer.

En ambos casos, debes relacionar de alguna forma cada componente que creas con el hilo correspondiente, de tal forma que cuando un hilo finaliza su ejecución sepas qué componentes has de destruir.

Otra cosa que te recomiendo, es que incluyas un try-except en tu evento onExecute, englobando todo el código, para que puedas controlar mejor la destrucción de los componentes que creas y no se te quede ninguno cargado en memoria.

Espero haberte ayudado de alguna forma.

Si tienes más dudas, pregunta sin problemas.

un saludo.
Responder Con Cita
  #6  
Antiguo 19-07-2010
Avatar de richy08
richy08 richy08 is offline
Miembro
 
Registrado: may 2007
Ubicación: Bucerias, Nayarit Mexico
Posts: 529
Poder: 20
richy08 Va por buen camino
Cita:
Empezado por manuc Ver Mensaje
Hola richy08,

En ambos casos, debes relacionar de alguna forma cada componente que creas con el hilo correspondiente, de tal forma que cuando un hilo finaliza su ejecución sepas qué componentes has de destruir.

un saludo.
gracias manuc ahora tengo mas claro el comportamiento de los hilos, solo me queda una ultima duda en el codigo arriba les voy dando un nombre a cada componenete, que se compone del nombre de la maquina+'caracter', pero al intentar accederlo por su nombre no logro hacerlo alguna otra idea de como podria distinguir que componnete se creo en cada hilo, o como poderlo acceder por el nombre que le he asignado.

saludos
Responder Con Cita
  #7  
Antiguo 19-07-2010
manuc manuc is offline
Miembro
 
Registrado: abr 2010
Posts: 165
Poder: 17
manuc Va por buen camino
Hola Richy08,

Pues sí, alguna te puedo dar.

Este código puede ser un poco más complicado de seguir al principio, pero creo que el más cómo, una vez lo tengas claro.

1.- Te Creas una nueva clase, para manejar tus componentes:

Código Delphi [-]
type
  tmisComponentes=Class(tPersistent)
  private
   fConexion:TSQLConnection;
   fQuery:TDataSet;
  Public
   destructor Destroy;
   property Conexion:TSQLConnection read fConexion write fConexion;
   property Query:TDataSet read fQuery write fQuery;
  end;

Cambia el tipo de componetes que quieras crear.

2.- Al recibir la conexión en el tcpServer Creamos los componentes:

Código Delphi [-]
procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
var
 MisComponentes:tmisComponentes;
begin
 MisComponentes := tmisComponentes.Create;
 MisComponentes.Conexion := TSQLConnection.Create(self);
 MisComponentes.Query := TDataSet.Create(Self);

 AThread.Data := @MisComponentes;

end;

3.- ¿Cómo usarlos?

Código Delphi [-]
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
 MisComponentes:tmisComponentes;
begin
 MisComponentes :=  tmisComponentes(AThread.Data);

 MisComponentes.Query ....

end;

4.- Como destruirlos:

Código Delphi [-]
procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);
var
 MisComponentes:tmisComponentes;
begin
 MisComponentes :=  tmisComponentes(AThread.Data);

 MisComponentes.Conexion.Free;
 MisComponentes.Query.Free;

 ...

end;

Básicamente, lo que se haces es "recordar" la dirección de memoria donde están localizados los componentes, utilizando para ello un "puntero" que tiene cada conexión (.data).

Lo he hecho de cabeza y sin compilarlo. Puede ser que me haya equivocado en algo, pero básicamente lo puedes hacer así.

Si encuentra alguna duda, consulta sin problemas.

Un saludo.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Como instalar los componenetes de la Norma 19 diego11 Varios 3 17-10-2007 12:08:44
componenetes en un TTabControl lucasarts_18 OOP 2 27-09-2005 23:44:43
instalar nuevos componenetes aranel OOP 6 02-08-2005 09:25:33
Multiple Hilos con Indy en Delphi 6 cancerbero Varios 4 12-06-2004 19:01:21
Componenetes para envio y recepcion de mensajes en la red enrique800 OOP 3 29-01-2004 04:31:41


La franja horaria es GMT +2. Ahora son las 01:53:22.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi