Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Problem mit SendStream und ReceiveBuf bei großen Dateien (https://www.delphipraxis.net/109308-problem-mit-sendstream-und-receivebuf-bei-grossen-dateien.html)

hugo1990 27. Feb 2008 20:36


Problem mit SendStream und ReceiveBuf bei großen Dateien
 
Wenn ich folgendermaßen mit TClientSocket und TServerSocket Dateien versende:

Client:
Delphi-Quellcode:
procedure TFileClient.SendData;
begin
  FClient.Socket.SendStream(FileStream);
end;
Server:
Delphi-Quellcode:
procedure TFileServer.ReceiveData(Sender: TObject; Socket: TCustomWinSocket);
var
  Buffer: AnsiString;
  Size: Integer;
begin
  Size := Socket.ReceiveLength;
  SetLength(Buffer, Size);
  Socket.ReceiveBuf(Buffer[1], Size);
  FileStream.Write(Buffer[1], Size);
end;
bekomme ich die Meldung "Windows-Socket-Fehler: Eine vorhandene Verbindung wurde vom Remotehost geschlossen." Ich nehme mal an, das das so eine Art Timeout vom Server ist. Bin ich da richtig in der Annahme und wenn ja, wie kann man das ausschalten oder verlängern?

SirThornberry 27. Feb 2008 20:47

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien
 
also kommt der Fehler beim Server? Ich würde versuchen das ganze einfach stückenweise zu schicken wenn es nur bei großen Dateien auftritt. Ist das was du gepostet hast der vollständige Quelltext? Hast du bedacht das der Stream nicht vollständig ankommt sondern stückenweise (ReceiveData also mehrfach aufgerufen wird)?

hugo1990 28. Feb 2008 20:34

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien
 
Also ich habe das jetzt so umgeschrieben, das es Stückenweise verschickt wird, aber der Fehler tritt trotzdem noch bei großen Dateien (so um die 90 KB, also eigentlich nicht wirklich groß) auf. Also es tritt der Socket-Fehler 10053 auf, was woll so viel bedeutet, wie das der Server den Clienten gekickt hat, aber warum, ist das so ne art timeout?

Edit: Ok ich habe jetzt nochmal ein wenig rumprobiert und mitbekommen, der der Fehler immer auftritt, wenn ca. 65 KB versendet wurden, also scheint das nicht an der Zeit zu liegen, weiß jemand, woran das liegt, das der Server immer bei ca. 65 KB die Verbindung zum Server trennt.

Muetze1 29. Feb 2008 00:16

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien
 
64 KB ist der interne Socket Buffer. Scheint mir so, als wenn der Server die Verbindung kickt, da der Buffer überläuft. Kann es sein, dass das Empfangsereignis nicht richtig verknüpft ist beim Server und daher der Buffer voll läuft?

hugo1990 29. Feb 2008 07:08

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien
 
Als Empfangsereignis nutze ich vom Server das OnClientRead-Ereignis, das müsste doch richtig sein, oder liege ich da falsch?

hugo1990 1. Mär 2008 12:14

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien
 
Ich poste jetzt einfach mal de gesamten Quellcode, vllt kann mir ja dann jemand sagen, was ich falsch mache, dass der Server den Clienten immer nach der Übertragung von 64 KB kickt.
Delphi-Quellcode:
unit uFileTransfer;

interface

uses
  ScktComp, Classes, SysUtils, Windows;
 
type
  TFileServer = class(TPersistent)
  protected
    FServer: TServerSocket;
    FFiles: TFiles;
    FTime: Longword;
  private
    procedure ReceiveData(Sender: TObject; Socket: TCustomWinSocket);
    function GetFileInfo(var Text: AnsiString): TFileInfo;
    function GetFileInfo2(Index: Integer): TFileInfo2;
    function CountFiles: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Start;
    property Files[Index: Integer]: TFileInfo2 read GetFileInfo2;
    property FilesCount: Integer read CountFiles;
  end;
  TFileClient = class(TPersistent)
  protected
    FClient: TClientSocket;
    FFile: TSendFile;
    FTime: Longword;
  private
    procedure SendData(Sender: TObject; Socket: TCustomWinSocket);
  public
    constructor Create;
    destructor Destroy; override;
    procedure Start(ServerAdress: String);
    procedure SendFile(Filename: String);
  end;

implementation

constructor TFileServer.Create;
begin
  inherited;
  FServer := TServerSocket.Create(nil);
  FServer.OnClientRead := ReceiveData;
  FServer.Service := 'ftp';
  FFiles := TFiles.Create;
end;

destructor TFileServer.Destroy;
begin
  FServer.Free;
  FFiles.Free;
  inherited;
end;

procedure TFileServer.ReceiveData(Sender: TObject; Socket: TCustomWinSocket);
var Size: Integer;
    Text: AnsiString;
    FileInfo: TFileInfo;
    Time: LongWord;
begin
  while Socket.ReceiveLength > 0 do
    begin
    Size := Socket.ReceiveLength;
    SetLength(Text, Size);
    Socket.ReceiveBuf(Text[1], Size);
    if Pos(#5+'header'+#6,Text) > 0 then
      begin
      FileInfo := GetFileInfo(Text);
      FFiles.Add(FileInfo.Filename, FileInfo.Size, Integer(Socket));
      FFiles.Items[FFiles.IndexOf(Integer(Socket))].Write(Text[1], Length(Text));
      FTime := GetTickCount;
      end
    else
      begin
      FFiles.Items[FFiles.IndexOf(Integer(Socket))].Write(Text[1], Length(Text));
      end;
    Time := GetTickCount-FTime;
    if Time = 0 then Time := 1;
    FFiles.Items[FFiles.IndexOf(Integer(Socket))].Speed := Size*1000/Time;
    if FFiles.Items[FFiles.IndexOf(Integer(Socket))].FullSize = FFiles.Items[FFiles.IndexOf(Integer(Socket))].LoadedSize then
      begin
      FFiles.Save(FFiles.IndexOf(Integer(Socket)));
      end;
    FTime := GetTickCount;
    end;
end;

function TFileServer.GetFileInfo(var Text: AnsiString): TFileInfo;
var I, ParamNo, Start:Integer;
    Substring: String;
begin
  I := 0;
  ParamNo := 0;
  Start := 0;
  while (I < Length(Text)) and (Substring <> #6+'/header'+#7) do
    begin
    case Text[I] of
      #5:Substring := '';
      #6:begin
        case ParamNo of
          1:Result.Filename := copy(Text, Start, I-Start);
          2:Result.Size := StrToInt(copy(Text, Start, I-Start));
          end;
        inc(ParamNo);
        Start := I+1;
        Substring := '';
        end;
      end;
    Substring := Substring+Text[I];
    inc(I);
    end;
  if Text[I] = #7 then inc(I);
  Text := copy(Text, I, Length(Text));
end;

function TFileServer.GetFileInfo2(Index: Integer): TFileInfo2;
begin
  Result.FullSize := FFiles.Items[Index].FullSize;
  Result.LoadedSize := FFiles.Items[Index].LoadedSize;
  Result.Filename := FFiles.Items[Index].Filename;
  Result.Speed := FFiles.Items[Index].Speed;
end;

function TFileServer.CountFiles: Integer;
begin
  Result := FFiles.Count;
end;

procedure TFileServer.Start;
begin
  FServer.Open;
end;

constructor TSendFile.Create(Filename: String);
begin
  inherited Create;
  FFile := TMemoryStream.Create;
  FFile.LoadFromFile(Filename);
  FFilename := Filename;
end;

constructor TFileClient.Create;
begin
  inherited;
  FClient := TClientSocket.Create(nil);
  FClient.OnConnect := SendData;
  FClient.Service := 'ftp';
end;

destructor TFileClient.Destroy;
begin
  FClient.Free;
  FFile.Free;
  inherited;
end;

procedure TFileClient.SendData(Sender: TObject; Socket: TCustomWinSocket);
var Header: AnsiString;
begin
  if Assigned(FFile) then
    begin
    Header := '';
    if FFile.Stream.Position = 0 then
      begin
      Header := #5+'header'+#6+ExtractFileName(FFile.Filename)+#6+IntToStr(FFile.Stream.Size)+#6+'/header'+#7;
      Socket.SendBuf(Header[1], Length(Header));
      end;
    Socket.SendStream(FFile.Stream);
    end;
end;

procedure TFileClient.Start(ServerAdress: String);
begin
  FClient.Host := ServerAdress;
  FClient.Open;
end;

procedure TFileClient.SendFile(Filename: String);
begin
  FFile := TSendFile.Create(Filename);
  if FClient.Active then SendData(Self, FClient.Socket);
end;

end.

hugo1990 1. Mär 2008 16:35

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien
 
Ok, das ganze liegt nicht am Quellcode sondern am Rechner oder Betriebssytem. Ich habe das ganze nähmlich jetzt auf meinem alten rechner mit XP getestet und der Fehler tritt nicht auf, bei meinem neuen mit Vista tritt der Fehler auf.

Edit: Ich habs, es liegt an der Windows-Firewall, die hab ich nämlich auf dem Vista-Rechner laufen, auf dem XP-Rechner hab ich ne andere. Als ich jetzt die Windows-Firewall deaktiviert habeging das ohne Probleme. Kennt jemand dieses Problem und weiß wie man das lösen kann ohne die Windows-Firewall zu deaktivieren.

Muetze1 1. Mär 2008 19:47

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien
 
Folgendes zu deinem bisherigen Code:

- du müsstest definitv Warnungen vom Compiler bekommen, da du z.B. SubString bei GetFileInfo() nicht vor der ersten Abfrage initialisierst, etc (glücklicherweise macht das Delphi aufgrund der Referenzzählung)
- Du suchst nach dem Teil string zur Teilung als ganzes. Was ist aber wenn in dem empfangenen Block gerade mal "#6/head" angekommen ist? Dann findest du es nicht, schreibst es so weg. Damit ist die empfangene Datei schon verändert und du bekommst niemals diese Trennung mehr raus.
- Was ist, wenn in dem empfangen Block Restdaten vom File sind und ein Header vom nächsten File? Ich sehe nicht, wo du diesen Rest noch in die alte Datei schreibst...
- Die Funktion GetFileInfo() ist recht unperformant, wenn du die Zeichen einzelnd kopierst anstatt als Block von Text[] zu SubString
- Warum nutzt du die Service Eigenschaften der Sockets und belegst damit definierte Protkolle anstatt dir einfach einen freuen Port zu schnappen?
- Warum ziehst du dir bei TSendFile die komplette Datei in einen Memorystream? Versende dann mal bitte ein 4,7 GB DVD Image mit der Komponente... Mit anderen Worten: Warum nicht allgemein TStream und du übergibst bei einer Datei explizit TFileStream Instanz?

Nur mal so beim rüberfliegen. Kann natürlich sein, dass ich manches falsch bzw. nicht gesehen habe...

hugo1990 2. Mär 2008 14:06

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien
 
Das der Code noch nicht ganz perfekt ist, ist mir schon klar, das habe ich noch nicht weiter gemacht gehabt, da der Fehler der aufgetretten ist gar nichts damit zu tun hatte. Ich wollte erst den Fehler behoben haben, bevor ich das dann weitermache. Aber trotzdem danke für den Hinweis.


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:39 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz