Cita:
Empezado por Faust
Muy ilustrativo amigo Sintecsl...
Me gustó mucho tu ejemplo, me ha aclarado algunas cosas, solo algunas preguntas... en cuanto al tamaño del buffer para el envío y recepción ¿te refieres a la propiedad RecvBufferSize y SendBufferSize del client? ¿el server tiene alguna parecida o se ajusta al client?, ¿este tamaño puede ser modificado una vez que se ha conectado el cliente?
Bueno... creo que ya he dado mucha lata.
Por último, veo que eres nuevo en el club y sería bueno que cooperaras más seguido con nosotros y también a nombre del club te ofrezco el apoyo de los demás compañeros .
Gracias de antemano y buen inicio de semana.
|
A tu pregunta el
buffer, la respuesta es que si se puede manipular tanto en el cliente (lo mas facil) como en el server.
En la propiedad del buffer cuando te pasa la variable el cliente se establece para dicha conexión esa variable de forma automática en
Indy.
En el server si quieres cambiar ese buffer puedes poner una instrucción o comando :
Código Delphi
[-]
procedure TServerForm.ServerCAMBIATAMANOBUFFERCommand(ASender: TIdCommand);
begin
Try
ASender.Thread.Connection.RecvBufferSize:=ASender.Thread.Connection.ReadInteger();
ASender.Thread.Connection.SendBufferSize:=ASender.Thread.Connection.RecvBufferSize;
Except End
end;
Esto es útil porque en mi caso envío/recepciono de forma comprimida ficheros.
Y establezco la compresión al conectar con esta instrucción :
Código Delphi
[-]
procedure TServerForm.ServerNIVELCOMPRESIONCommand(ASender: TIdCommand);
begin
NivelCompress:=TZCompressionLevel(ASender.Thread.Connection.ReadInteger());
FormStorage1.StoredValues.Values['NivelCompresion'].Value:=
Integer(NivelCompress);
FormStorage1.StoredValues.SaveValues;
end;
Lo cual me permite ajustar el ancho de banda de conexión.
Por otro lado, en el envío/recepción de ficheros determino el buffer a la mitad del que tiene cada conexión (el buffer está guardado en cada variable tipo hilo (ASender)). Esto es motivo para evitar desbordamientos en ficheros muy comprimidos y que superan el tamaño original, lo cual te daría errores insalvables.
Como ejemplo un boton :
EL CLIENTE :
Código Delphi
[-]
procedure TCopiaFiles.CopiaAlServer(const Origen, Destino: String);
Var
Error, TamanoPaq, NPaq, Leidos, Escritos, x, Parar : Integer;
FHandle : Integer;
Buf, BufOut : Pointer;
SFile : TFileStream;
begin
try If (Not Cliente.Connected)Or(EnEjecucion)Or(PararEnvioRecepcion) Then Exit;
EnEjecucion:=True; LimpiaPantalla; Enviando; Cliente.Writeln('COPIAFILEDECLIENTE'); Cliente.Writeln(Destino);
Recibiendo; Error:=Cliente.ReadInteger();
If Error=13000 Then Begin
Parar:=0;
If Sobreescritura Then Parar:=Application.MessageBox('¿ SOBREESCRIBIR ?','ATENCIÓN',
MB_YESNOCANCEL+mb_IconQuestion);
If Parar=idNo Then
Begin
Cliente.WriteInteger(1); EnEjecucion:=False;
Exit
End
Else
If Parar=idCancel Then
Begin
Cliente.WriteInteger(1); PararEnvioRecepcion:=True;
EnEjecucion:=False;
Exit
End
End
Else If Error<>0 Then
Begin
Cliente.WriteInteger(1); If Error=800 Then
ShowMessage(' NO SE PUDO CREAR EL DIR :'#13
+ExtractFilePath(Destino));
EnEjecucion:=False;
Exit
End;
Enviando; Cliente.WriteInteger(0);
SFile:=TFileStream.Create(Origen,fmShareDenyRead);
TamanoPaq:=Cliente.SendBufferSize Div 2;
GetMem(Buf,TamanoPaq);
NPaq:=SFile.Size Div TamanoPaq;
If (SFile.Size/TamanoPaq)>0.0 Then Inc(NPaq);
BarraProgresoFichero.ValorMax:=SFile.Size;
Cliente.WriteInteger(NPaq);
CronoHP1.Activa(1);
For x:=1 To NPaq Do
Begin
CronoHP1.Activa(2);
Leidos:=SFile.Read(Buf^,TamanoPaq);
ZCompress(Buf,Leidos,BufOut,Escritos,NivelCompress);
Application.ProcessMessages;
If PararEnvioRecepcion Then
Begin Cliente.WriteInteger(1); FreeMem(BufOut);
FreeMem(Buf);
SFile.Free;
BarraProgresoFichero.ValorMax:=0;
EnEjecucion:=False;
Exit
End
Else Cliente.WriteInteger(0);
Cliente.WriteInteger(Escritos);
Retardo; Cliente.WriteBuffer(BufOut^,Escritos);
FreeMem(BufOut);
BarraProgresoFichero.Progress:=SFile.Position;
Velocidad.Caption:=Format('%n KBytes/Seg',
[Leidos/(CronoHP1.Read_r(2,fcSeg)*1024)]);
If x>1 Then
Begin
VelocidadMedia.Caption:=Format('%n KBytes/Seg',
[SFile.Position/
(CronoHP1.Read_r(1,fcSeg)*1024)]);
TiempoRestante.Caption:=DameTiempoEnHMS(Round(((SFile.Size-SFile.Position)*
CronoHP1.Read_r(1,fcSeg)
/SFile.Position)));
TiempoTranscurrido.Caption:=DameTiempoEnHMS(CronoHP1.Read_i(1,fcSeg));
End;
End;
BarraProgresoFichero.Progress:=0;
FreeMem(Buf);
SFile.Free;
Enviando; FHandle:=FileOpen(Origen, fmShareDenyRead);
Cliente.WriteInteger(FileGetAttr(Origen));
Cliente.WriteInteger(FileGetDate(FHandle));
FileClose(FHandle);
EnEjecucion:=False;
Except EnEjecucion:=False;
ShowMessage('¡¡¡ ERROR GRAVE !!!'#13'SALDREMOS DEL PROGRAMA');
Self.Close;
Halt
End
end;
procedure TCopiaFiles.CopiaDelServer(const Origen, Destino: String);
Var
Error, NPaq, TamanoPaq, TamFichero,
Leidos, Escritos, x, Parar : Integer;
FHandle : Integer;
SFile : TFileStream;
Buf, BufIn : Pointer;
Dir : String;
begin
Try If (Not Cliente.Connected)Or(EnEjecucion) Then Exit;
EnEjecucion:=True; LimpiaPantalla; Enviando; Cliente.Writeln('COPIAFILEDESERVER'); Cliente.Writeln(Origen);
Recibiendo; Error:=Cliente.ReadInteger();
If Error<>0 Then Exit;
Dir:=ExtractFilePath(Destino);
If Not DirectoryExists(Dir) Then Begin
If Not ForceDirectories(Dir) Then
Begin
Cliente.WriteInteger(1); EnEjecucion:=False;
Exit
End
End;
If FileExists(Destino) Then
Begin
Parar:=0; If Sobreescritura Then Parar:=Application.MessageBox('¿ SOBREESCRIBIR ?','ATENCIÓN',
MB_YESNOCANCEL+mb_IconQuestion);
If Parar=idNo Then
Begin
Cliente.WriteInteger(1); EnEjecucion:=False;
Exit
End
Else
If Parar=idCancel Then
Begin
Cliente.WriteInteger(1); PararEnvioRecepcion:=True;
EnEjecucion:=False;
Exit
End
End;
Enviando; Cliente.WriteInteger(0); TamanoPaq:=Cliente.SendBufferSize Div 2;
BorraFichero(Destino);
SFile:=TFileStream.Create(Destino,fmCreate);
Recibiendo; TamFichero:=Cliente.ReadInteger();
NPaq:=Cliente.ReadInteger();
BarraProgresoFichero.ValorMax:=TamFichero;
CronoHP1.Activa(1);
For x:=1 To NPaq Do
Begin
CronoHP1.Activa(2);
Application.ProcessMessages;
Enviando; If PararEnvioRecepcion Then
Begin Cliente.WriteInteger(1); SFile.Free;
DeleteFile(Destino); BarraProgresoFichero.ValorMax:=0;
EnEjecucion:=False;
Exit
End
Else Cliente.WriteInteger(0);
Recibiendo; Leidos:=Cliente.ReadInteger();
GetMem(BufIn,Leidos);
Cliente.ReadBuffer(BufIn^,Leidos);
Retardo; ZDecompress(BufIn,Leidos,Buf,Escritos,TamanoPaq);
SFile.Write(Buf^,Escritos);
FreeMem(Buf);
FreeMem(BufIn);
BarraProgresoFichero.Progress:=SFile.Size;
Velocidad.Caption:=Format('%n KBytes/Seg',
[Escritos/(CronoHP1.Read_r(2,fcSeg)*1024)]);
If x>1 Then
Begin
VelocidadMedia.Caption:=Format('%n KBytes/Seg',
[SFile.Size/
(CronoHP1.Read_r(1,fcSeg)*1024)]);
TiempoRestante.Caption:=DameTiempoEnHMS(Round((TamFichero-SFile.Size)
*CronoHP1.Read_r(1,fcSeg)
/SFile.Size));
TiempoTranscurrido.Caption:=DameTiempoEnHMS(CronoHP1.Read_i(1,fcSeg));
End;
End;
SFile.Free;
Recibiendo; FHandle:=FileOpen(Destino, fmOpenWrite);
FileSetAttr(Destino,Cliente.ReadInteger);
FileSetDate(FHandle,Cliente.ReadInteger);
FileClose(FHandle);
BarraProgresoFichero.ValorMax:=0;
EnEjecucion:=False;
Except EnEjecucion:=False;
ShowMessage('¡¡¡ ERROR GRAVE !!!'#13'SALDREMOS DEL PROGRAMA');
Self.Close;
Halt
End
end;
EL SERVER (solo es la copia desde el cliente al server) :
Código Delphi
[-]
procedure TServerForm.ServerCOPIAFILEDECLIENTECommand(ASender: TIdCommand);
Var
Fichero, Dir : String;
Error, NPaq, Leidos, Escritos, TamanoPaq, x : Integer;
FHandle : Integer;
SFile : TFileStream;
BufIn, Buf : Pointer;
begin
Try
Fichero:=ASender.Thread.Connection.ReadLn;
Dir:=ExtractFilePath(Fichero);
If Not DirectoryExists(Dir) Then Begin
If Not ForceDirectories(Dir) Then Error:=800 Else Error:=0; End
Else
If FileExists(Fichero) Then Error:=13000 Else Error:=0;
ASender.Thread.Connection.WriteInteger(Error);
Error:=ASender.Thread.Connection.ReadInteger();
If Error<>0 Then Exit;
BufIn:=Nil;
UtilidadFiles.BorraFichero(Fichero);
SFile:=TFileStream.Create(Fichero,fmCreate);
TamanoPaq:=ASender.Thread.Connection.RecvBufferSize Div 2;
NPaq:=ASender.Thread.Connection.ReadInteger();
For x:=1 To NPaq Do
Begin
If ASender.Thread.Connection.ReadInteger>0 Then
Begin SFile.Free;
UtilidadFiles.BorraFichero(Fichero);
Exit
End;
Leidos:=ASender.Thread.Connection.ReadInteger();
GetMem(BufIn,Leidos);
ASender.Thread.Connection.ReadBuffer(BufIn^,Leidos);
ZDecompress(BufIn,Leidos,Buf,Escritos,TamanoPaq);
SFile.Write(Buf^,Escritos);
FreeMem(Buf);
FreeMem(BufIn);
End;
If Assigned(SFile) Then SFile.Free; FHandle:=FileOpen(Fichero, fmOpenWrite);
SetFileAttributes(PChar(Fichero),ASender.Thread.Connection.ReadInteger);
FileSetDate(FHandle,ASender.Thread.Connection.ReadInteger);
FileClose(FHandle);
Except If Assigned(SFile) Then SFile.Free; End
end;
Como verás cada conexión tiene su propio buffer pero que lo que importa es como se gestiona.
Ya sé que hay parámetros que no entenderás o que no están documentados pero pertenecen a mi programa y son muy extensos de explicar y de documentar....
Espero que te sea ilustrativo lo anteriormente mencionado.
No soy programador. Solo ingeniero. Por lo que esto para mí es una aficción útil pero nada mas.
Saludos a todos.