Una posible solución es enviar el archivo y luego desconectar, de esta forma solo tendríamos que leer, en el lado del servidor, hasta que la conexión se cierre.
Por ejemplo:
Código Delphi
[-]
const
BufferSize = 32 * 1024;
procedure TfrmMain.ServidorAccept(Sender: TObject;
ClientSocket: TCustomIpClient);
var
Buffer: PByte;
Recibidos: Integer;
begin
with TFileStream.Create(ClientSocket.Receiveln, fmCreate) do
try
GetMem(Buffer,BufferSize);
try
Recibidos:= ClientSocket.ReceiveBuf(Buffer^,BufferSize);
while Recibidos > 0 do
begin
WriteBuffer(Buffer^,Recibidos);
Recibidos:= ClientSocket.ReceiveBuf(Buffer^,BufferSize);
end;
finally
FreeMem(Buffer);
end;
finally
Free;
end;
end;
El cliente lo implemento dentro de un thread, ya que voy a colocar la propiedad BlockMode = bmBlocking y no quiero que se me bloquee el resto de la aplicación. Aunque puede parecer complicado, esto nos permitirá mandar varios archivos a la vez y también cancelar el envió antes de que termine.
El thread cliente, que yo llamare TEnvio, lo implemento asi:
Código Delphi
[-]
TEnvio = class(TThread)
private
FCliente: TTCPClient;
FLocalFile: String;
FRemoteFile: String;
protected
procedure Execute; override;
public
constructor Create(LocalFile,RemoteFile,Host,Port: String);
destructor Destroy; override;
end;
constructor TEnvio.Create(LocalFile,RemoteFile,Host,Port: String);
begin
inherited Create(FALSE);
FreeOnTerminate:= TRUE;
FLocalFile:= LocalFile;
FRemoteFile:= RemoteFile;
FCliente:= TTCPClient.Create(nil);
FCliente.RemoteHost:= Host;
FCliente.RemotePort:= Port;
FCliente.BlockMode:= bmBlocking;
end;
destructor TEnvio.Destroy;
begin
FCliente.Free;
inherited;
end;
procedure TEnvio.Execute;
var
Buffer: PByte;
Leidos: Integer;
begin
inherited;
with TFileStream.Create(FLocalFile,fmOpenRead or fmShareDenyWrite) do
try
GetMem(Buffer,BufferSize);
try
FCliente.Active:= TRUE;
try
FCliente.Sendln(FRemoteFile);
Leidos:= Read(Buffer^,BufferSize);
while (Leidos > 0) and not Terminated do
begin
FCliente.SendBuf(Buffer^,Leidos);
Leidos:= Read(Buffer^,BufferSize);
end;
finally
FCliente.Active:= FALSE;
end;
finally
FreeMem(Buffer);
end;
finally
Free;
end;
end;
Un ejemplo de como usar lo anterior:
Código Delphi
[-]
var
Envio: TEnvio;
begin
with TOpenDialog.Create(nil) do
try
if Execute then
begin
Envio:= TEnvio.Create(Filename, 'C:\' + ExtractFileName(Filename),
txtHost.Text, '2000');
end;
finally
Free;
end;
end;
En cualquier momento podemos cancelar la transmisión utilizando "Envio.Terminate". Pero te dejo a ti escoger cuando y donde utilizar esa opción. Otras mejoras pueden ser que la ruta del archivo remoto sea relativa y no absoluta, por motivos de seguridad, o enviar junto con el archivo su hash md5 para comprobar que ha llegado bien. Pero eso lo podemos dejar para mas adelante ...
Aquí te dejo el proyecto envuelto para regalo ...