Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Internet
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 15-04-2007
JMGR JMGR is offline
Miembro
 
Registrado: jun 2003
Ubicación: Santa Cruz de Tenerife
Posts: 46
Poder: 0
JMGR Va por buen camino
Transferencia de archivos con sockets

Buenas...

Antes de nada decir que he buscado y rebuscado tanto en los foros como en el google sobre este tema y aunque me he quemado las pestañas leyendo, intentando comprender y probando todo lo que he encontrado no hay manera... no he encontrado un solo ejemplo que me funcione...

Para empezar no he encontrado por ningun lado la demo de las Indy que nombran en este hilo ya que con mi Delphi 5 no venian incluidas y en la version 10 que me baje de internet tampoco, y en la pagina no lo encuentro. El ejemplo de Zarko Gajic aqui tampoco me vale porque en la version 10 de las Indy ya no se usa AThread: TIdPeerThread como parametro sino AContext: TIdContext y no se como adaptarlo.
Este ejemplo tampoco me funciona, no me da error simplemente no hace nada...
Y asi una lista bastante larga...

Uso Delphi 5 y los componentes Sockets que trae. Es una aplicacion para mandar y recibir determinados archivos entre cliente y servidor. Lo tipico es un servidor que recibe demandas del cliente, lo que pasa es que si hay un router entonces hay que configurarlo para poder conectar cliente y servidor. Para evitar esto lo que hago es usar la aplicacion cliente como servidor, es decir, el cliente comprueba cada segundo si hay alguna peticion del servidor, que ejecuto yo con mi router ya configurado. Ya he conseguido ver y seleccionar las carpetas del cliente desde el servidor pero a la hora de recibir/mandar los archivos no hay forma...y no se por que

Este es el codigo del cliente para enviar el archivo:
Código Delphi [-]
procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var
 params, com, uni:string;
 i:integer;
 Stream:TFilestream;
begin
timer1.enabled:=false;//Deja de comprobar si hay peticiones
comando:=Socket.ReceiveText;
params:=copy(comando,6,length(comando)-5);//Aqui recibe el nombre del archivo
com:=copy(comando,1,4);
  if com='DAME' then
   begin
     archivos:=params;
     stream:=TFileStream.Create(archivos,fmOpenRead or fmShareDenywrite);
     sleep(200);
     socket.SendText('TOMA '+inttostr(Stream.size));
     sleep(200);
     socket.SendStream(stream);
   end;

Y lo que no tengo claro todavia es el codigo del servidor, que por cierto esta sacado de la Biblia de Delphi 5, de Marco Cantú:
Código Delphi [-]
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  size: Integer;
  strcom, com:string;
  nreceived,i:integer;
  Stream:  TMemoryStream;
begin
 strcom:=Socket.ReceiveText;
 if pos('TOMA',strcom)=1 then
  begin
        Stream := TMemoryStream.Create;
        Screen.Cursor := crHourglass;
        try
          while True do
          begin
            nReceived := Socket.ReceiveBuf (Buffer, sizeof (Buffer));
            if nReceived <= 0 then
              Break
            else
              Stream.Write (Buffer, nReceived);
            Sleep (200);
          end;
          Stream.Position := 0;
          stream.SaveToFile('C:\Prueba\dummy.txt');
        finally
          Stream.Free;
          Screen.Cursor := crDefault;
        end;m.free;
  end;

Esto me crea un archivo pero vacio, es decir,con cero kb. Creo, despues de todo lo que he leido y lo poco que he sacado en claro, que es porque de alguna manera hay que esperar a que termine de rellenarse el stream, que se comprueba comparando el tamaño del archivo con la cantidad recibida, pero, en teoria, ¿de esto no se encargan las lineas?:
Código Delphi [-]
            nReceived := Socket.ReceiveBuf (Buffer, sizeof (Buffer));
            if nReceived <= 0 then
              Break
            else
              Stream.Write (Buffer, nReceived);
Pero tambien he leido aqui que:
Código:
2)You need to store the received data globally, otherwise it will be
lost in the next call of the event, you already do this with your
stream. Just make sure the stream is not freed inside the event.
Por lo que entiendo que debo rellenar el stream pero fuera del evento OnRead, pero ¿ como?

Conclusion: Ni idea...

¿En que me estoy equivocando?
¿Como se puede hacer?
¿Algun trozo de codigo que funcione 100%?
¿Alguna sugerencia?

Gracias y un saludo. Y perdon por el rollo y el interrogatorio final...
JMGR
Responder Con Cita
  #2  
Antiguo 15-04-2007
Avatar de poliburro
[poliburro] poliburro is offline
Miembro Premium
 
Registrado: ago 2004
Ubicación: México D.F
Posts: 3.068
Poder: 23
poliburro Va por buen camino
Existe un proyecto opensource de un cliente p2p que puede ser de tu ayuda,

puedes buscarlo en SourceForge. :P,
__________________
Conoce mi blog http://www.edgartec.com
Responder Con Cita
  #3  
Antiguo 16-04-2007
JMGR JMGR is offline
Miembro
 
Registrado: jun 2003
Ubicación: Santa Cruz de Tenerife
Posts: 46
Poder: 0
JMGR Va por buen camino
Gracias por la respuesta poliburro pero es que ya tengo muy avanzada la aplicacion como pa meterme ahora a investigar p2p...

De todas maneras ya lo consegui y voy a explicar mis conclusiones por si a alguien le hace falta:

1- Efectivamente, hay que rellenar el Stream en la llamada al evento OnRead correspondiente al envio, es decir, el cliente envia una palabra clave para indicar que a continuacion se va a enviar un stream:
Código Delphi [-]
procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
begin
   socket.SendText('TOMASTREAM');//<--Mandamos la palabra clave
   socket.SendStream(stream);//<--Y a continuacion mandamos el stream
end;

El servidor recibe la palabra clave y se dispara el evento OnRead, la palabra clave le indica que la proxima vez que se dispare OnRead va a recibir el stream, recibiendo la cantidad transferida en Socket.ReceiveBuf pero, y he aqui lo importante, SOLO EN LA PROXIMA LLAMADA A OnRead, es decir, si se dispara otra vez OnRead y se vuelve a llamar a Socket.ReceiveBuf ya no contendra la informacion...¿ como solucionarlo? Pues mi solucion ha sido controlar con un contador si se ha recibido la palabra clave en cuyo caso la siguiente vez que se dispare OnRead espero a rellenar el stream...no se si quedo claro pero igual el codigo ayuda:
Código Delphi [-]
procedure TForm1.FormCreate(Sender: TObject);
begin
 vez:=0;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
 nReceived:integer;
 Buffer: array [0..99999] of char;
 Stream:TMemoryStream;
begin
[...] 
//IMPORTANTE Lo primero que hacemos en el evento OnRead es controlar si hemos recibido la palabra clave
//Esta es la parte que se encarga del stream
if vez=1 then//<--Controlamos si en la llamada anterior hemos recibido la palabra clave
  begin
    vez:=0;//<--Reiniciamos el contador y creamos el stream
    Stream := TMemoryStream.Create;
    Screen.Cursor := crHourglass;
      try
        while True do
        begin
          nReceived := Socket.ReceiveBuf (Buffer, sizeof (Buffer));//<--Controla la cantidad de datos recibida
          if nReceived <= 0 then//<--Si ya no se reciben datos, es decir, al terminar la transferencia
            Break
          else
            Stream.Write (Buffer, nReceived);//<--Vamos rellenando el stream
          Sleep (200);
        end;
        Stream.Position := 0;
        stream.SaveToFile(directorio+nombre);
      finally
      end;
    Stream.Free;
    Screen.Cursor := crDefault;
    exit;
  end;

if (pos('TOMASTREAM',strcom)=1) and (vez<2) then //<--Al recibir la palabra clave aumentamos el contador
  begin
    vez:=vez+1;
    exit;
  end;
end;

end;

Evidentemente se podria usar un boolean para controlar la recepcion de la palabra clave pero acabo de conseguir que funcione y no lo he optimizado todavia...
Un detalle importante es que en el evento OnRead debemos controlar si se va a recibir el stream antes de acceder a la informacion del Socket, es decir, antes de llamar a socket.receivetext o socket.receivebuf, para rellenarlo

Espero que se haya entendido algo...

Un saludo!
JMGR
Responder Con Cita
Respuesta



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
velocidad de transferencia muy lenta lookmydoom Redes 1 26-08-2006 18:34:49
Transferencia lenta entre HDD ATA y HDD SATA Sergio J. Varios 1 22-04-2005 17:30:16
Velocidad de transferencia... eisenco Internet 0 21-03-2005 08:58:05
Transferencia FTP no se finaliza DarkByte Internet 0 05-03-2005 10:39:35
Transferencia de archivos Silver Varios 2 13-06-2003 23:12:38


La franja horaria es GMT +2. Ahora son las 14:28:28.


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