2

TServerSocket/を使用してファイルを送信しようとしていますTClientSocket。どこでもファイルストリームを解放しない限り、ファイルは完全に送信されform.OnCreateます。イベントも意味します。私がどこでも自由にすると、1 パーセントか 2 パーセントしか送られません。

TFileStream.Createまた、サーバー側OnCreateイベントにコード行を配置する必要があります。ストリームを作成すると、TForm2.ServerSocket1ClientReadEFcreateerror別のプロセスで使用されているため、プロセスはファイルにアクセスできません」というメッセージが表示されます。

procedure TForm2.FormCreate(Sender: TObject);
begin
    FStream := TFileStream.Create('c:\temp\log.txt', fmCreate or
    fmShareDenyWrite);
end;

procedure TForm2.ClientSocket1Connect(Sender: TObject;
    Socket: TCustomWinSocket);
var
  fs: TFileStream;

begin
    fs := TFileStream.Create('c:\log.txt', fmOpenRead);
    socket.SendStream(fs);
end;

procedure TForm2.ServerSocket1ClientRead(Sender: TObject;
    Socket: TCustomWinSocket);
var
    iLen: Integer;
    Bfr: Pointer;
begin
    iLen := Socket.ReceiveLength;
    GetMem(Bfr, iLen);
    Socket.ReceiveBuf(Bfr^, iLen);
    FStream.Write(Bfr^, iLen);
    FreeMem(bfr);
    //fstream.free
end;

コードをこのように配置しても:

if fstream.Size = fstream.position then
    fstream.free

それでも問題が発生します。

この奇妙な現象は何ですか?Delphiのバグですか?はいの場合、回避策はありますか? 問題がある場合: Delphi 2010 を使用しています。

更新:申し訳ありませんが、コードを次のように配置した場合:

if fileSize = fstream.position then
    fstream.free

申し訳ありませんfstream.sizeが、ではありませんfilesize。ファイル サイズを 300000 (受信するファイルのサイズ) として既に初期化しています。

解決済み:置き換えて解決

FStream := TFileStream.Create('c:\temp\log.txt',
                              fmCreate or fmShareDenyWrite);

if not FileExists('c:\temp\log.txt') then
    FStream := TFileStream.Create('c:\temp\log.txt',
                                  fmCreate or fmShareDenyWrite);
4

1 に答える 1

4

FStreamデータの最初のブロックを受け取るとすぐに、オブジェクトを解放しようとしています。そんなことしたらダメ。特に大きなファイルを送信する場合は、通常、そのブロックは完全なファイルよりも小さくなります。また、現在は常にストリームの最後にあるため、Position = Size常に評価されるため、受信側でのチェックも役に立ちません。他のディスカッションで既に説明したように、SendStream() メソッドと ReceiveBuf() メソッドを効果的に使用していないため、送信者はファイル データを送信する前にファイル サイズを送信する必要があります (または、ファイルの最後で切断する必要があります)。そのため、受信者は読み取りをいつ停止するかを正確に知っています。truePosition

編集: 次のようなことを試してください:

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; 
于 2010-07-20T19:38:03.463 に答える