AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Problem mit SendStream und ReceiveBuf bei großen Dateien
Thema durchsuchen
Ansicht
Themen-Optionen

Problem mit SendStream und ReceiveBuf bei großen Dateien

Ein Thema von hugo1990 · begonnen am 27. Feb 2008 · letzter Beitrag vom 2. Mär 2008
Antwort Antwort
hugo1990

Registriert seit: 27. Dez 2006
166 Beiträge
 
Turbo Delphi für Win32
 
#1

Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 27. Feb 2008, 20:36
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?
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#2

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 27. Feb 2008, 20:47
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)?
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
hugo1990

Registriert seit: 27. Dez 2006
166 Beiträge
 
Turbo Delphi für Win32
 
#3

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 28. Feb 2008, 20:34
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.
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#4

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 29. Feb 2008, 00:16
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?
  Mit Zitat antworten Zitat
hugo1990

Registriert seit: 27. Dez 2006
166 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 29. Feb 2008, 07:08
Als Empfangsereignis nutze ich vom Server das OnClientRead-Ereignis, das müsste doch richtig sein, oder liege ich da falsch?
  Mit Zitat antworten Zitat
hugo1990

Registriert seit: 27. Dez 2006
166 Beiträge
 
Turbo Delphi für Win32
 
#6

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 1. Mär 2008, 12:14
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.
  Mit Zitat antworten Zitat
hugo1990

Registriert seit: 27. Dez 2006
166 Beiträge
 
Turbo Delphi für Win32
 
#7

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 1. Mär 2008, 16:35
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.
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#8

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 1. Mär 2008, 19:47
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...
  Mit Zitat antworten Zitat
hugo1990

Registriert seit: 27. Dez 2006
166 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: Problem mit SendStream und ReceiveBuf bei großen Dateien

  Alt 2. Mär 2008, 14:06
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.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:41 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