您正在尝试在FStream
收到第一个数据块后立即释放您的对象。不要那样做。该块通常比完整文件小,尤其是在您发送大文件时。此外,Position = Size
在接收端检查也是无用的,因为它总是会评估,true
因为电流Position
总是在流的末尾。正如我在其他讨论中已经告诉您的那样,您没有有效地使用 SendStream() 和 ReceiveBuf() 方法,并且发送方需要在发送文件数据之前发送文件大小(或者在文件末尾断开连接)所以接收器确切地知道何时停止读取。
编辑:
尝试这样的事情:
type
TSocketBuffer = class
public
Stream: TStream;
ExpectedSize: Int64;
Data: array[0..1023] of Byte;
DataOffset, DataSize: Integer;
destructor Destroy; override;
end;
TServerSocketBuffer = class(TSocketBuffer)
public
FileName: String;
destructor Destroy; override;
end;
destructor TSocketBuffer.Destroy;
begin
if Stream <> nil then Stream.Free;
inherited;
end;
destructor TServerSocketBuffer.Destroy;
begin
if Stream <> nil then FreeAndNil(Stream);
if FileName <> '' then DeleteFile(FileName);
inherited;
end;
procedure TForm2.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
var
Buffer: TSocketBuffer;
begin
Buffer := TSocketBuffer.Create;
Socket.Data := Buffer;
// open the file to send...
Buffer.Stream := TFileStream.Create('c:\log.txt', fmOpenRead or fmShareDenyWrite);
Buffer.ExpectedSize := Buffer.Stream.Size;
// buffer the stream size...
Move(Buffer.Data[0], Buffer.ExpectedSize, Sizeof(Int64));
Buffer.DataOffset := 0;
Buffer.DataSize := SizeOf(Int64);
// begin sending...
ClientSocket1Write(Sender, Socket);
end;
procedure TForm2.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
TSocketBuffer(Socket.Data).Free;
end;
procedure TForm2.ClientSocket1Write(Sender: TObject; Socket: TCustomWinSocket);
var
Buffer: TSocketBuffer;
NumBytes: Integer;
begin
// in case OnWrite is fired before OnConnect...
if Socket.Data = nil then Exit;
Buffer := TSocketBuffer(Socket.Data);
if Buffer.Stream = nil then Exit;
// keep sending until EOF is reached, or until the socket blocks/errors...
repeat
// if there is pending data buffered, send it now...
while Buffer.DataOffset < Buffer.DataSize do
begin
NumBytes := Socket.SendBuf(Buffer.Data[Buffer.DataOffset], Buffer.DataSize-Buffer.DataOffset);
if NumBytes <= 0 then Exit; // wait for next event...
Inc(Buffer.DataOffset, NumBytes);
end;
// has EOF been reached?
if Buffer.ExpectedSize <= 0 then Break;
// read the next block of data from the stream...
Buffer.DataOffset := 0;
Buffer.DataSize := 0;
NumBytes := Buffer.Stream.Read(Buffer.Data[0], Min(Buffer.ExpectedSize, SizeOf(Buffer.Data)));
if NumBytes <= 0 then Break; // stream error, stop sending...
Buffer.DataSize := NumBytes;
Dec(Buffer.ExpectedSize, NumBytes);
// the next loop iteration will start sending it...
until False;
// all done...
FreeAndNil(Buffer.Stream);
Socket.Close;
end;
procedure TForm2.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
Socket.Data := TServerSocketBuffer.Create;
end;
procedure TForm2.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
TServerSocketBuffer(Socket.Data).Free;
end;
procedure TForm2.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
Buffer: TServerSocketBuffer;
FileName: String;
NumBytes: Integer;
begin
Buffer := TServerSocketBuffer(Socket.Data);
if Buffer.Stream = nil then
begin
// keep reading until stream size has been received in full...
while Buffer.DataSize < SizeOf(Int64) do
begin
NumBytes := Socket.ReceiveBuf(Buffer.Data[Buffer.DataOffset], SizeOf(Int64)-Buffer.DataOffset);
if NumBytes <= 0 then Exit; // wait for next event...
Inc(Buffer.DataSize, NumBytes);
Inc(Buffer.DataOffset, NumBytes);
end;
Move(Buffer.ExpectedSize, Buffer.Data[0], SizeOf(Int64));
// create the file to store in...
FileName := 'c:\temp\log.txt';
Buffer.Stream := TFileStream.Create(FileName, fmCreate);
Buffer.FileName := FileName;
// (optional) pre-size the file...
Buffer.Stream.Size := Buffer.ExpectedSize;
end;
// keep reading until EOF is reached, or until the socket blocks/errors...
while Buffer.ExpectedSize > 0 do
begin
// read the next block of data from the socket...
Buffer.DataOffset := 0;
Buffer.DataSize := 0;
NumBytes := Socket.ReceiveBuf(Buffer.Data[0], Min(Buffer.ExpectedSize, SizeOf(Buffer.Data)));
if NumBytes <= 0 then Exit; // wait for next event...
Buffer.DataSize := NumBytes;
// save the data to the stream....
repeat
NumBytes := Buffer.Stream.Write(Buffer.Data[Buffer.DataOffset], Buffer.DataSize-Buffer.DataOffset);
if NumBytes <= 0 then
// stream error, stop reading...
Socket.Close;
Exit;
end;
Inc(Buffer.DataOffset, NumBytes);
Dec(Buffer.ExpectedSize, NumBytes);
until Buffer.DataOffset >= Buffer.DataSize;
end;
// all done...
FreeAndNil(Buffer.Stream);
Buffer.FileName := '';
end;