Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Datei über DataSnap Verbindung senden (https://www.delphipraxis.net/126965-datei-ueber-datasnap-verbindung-senden.html)

WorstNightmare 5. Jan 2009 20:51

Datenbank: DataSnap • Version: 12 • Zugriff über: SQLConnection + SQLServerMethod

Datei über DataSnap Verbindung senden
 
Hallo,

ich "missbrauche" eine DataSnap Datenbank Verbindung für einen Remote-Explorer. Der Server läuft auf einem Rechner im Keller und der Client soll mir bestimmte Ordner auf seiner Festplatte anzeigen. Ich möchte nicht einfach normale Windows-Freigaben benutzen, da ich spezielle Shortcuts und andere Funktionen einbauen möchte. Nun bringt es mir nichts die Dateien einfach nur anzukucken, sondern würde ich sie auch gerne runter- und neue Inhalte hochladen.
Das Durchsuchen alleine klappt ganz gut, aber das Runterladen scheitert ab einer Dateigröße > 29 KB.
Die GetFile Methode auf dem Server sieht so aus:
Delphi-Quellcode:
function TDSServerModule1.GetFile(Filename: string): TMemoryStream;
begin
  Result := TMemoryStream.Create;
  Result.LoadFromFile(Filename);
end;
und der Client ruft sie so auf:
Delphi-Quellcode:
function TForm2.GetFile(Filename: string): Integer;
var
  Svr: TDSServerModule1Client;
begin
  Svr := TDSServerModule1Client.Create(SQLConnection1.DBXConnection);
  try
    Result := Svr.GetFile(Filename).Size;
  finally
    FreeAndNil(Svr);
  end;
end;
Und wiegesagt, wenn die angeforderte Datei > 29 KB, dann hat der MemoryStream eine Größe von -1. Lässt sich das irgendwie umgehen oder ist diese Datenbank einfach nicht dazu gemacht große Datenmengen aufeinmal zu übertragen? Ich möchte mich ungern mit Socketprotokollen etc. herumschlagen, diese Methode hier erscheint mir viel einfacher :-D

himitsu 19. Jan 2011 15:27

AW: Datei über DataSnap Verbindung senden
 
Hänge grade am selben Problem. :cry:

Ich hab aber schon rausgefunden, daß man Delphi-Referenz durchsuchenTDSTCPServerTransport.BufferKBSize auch ändern kann.
Durch dieses stehen für eine Übertragung insgesammt nur diese Datenmenge zur Verfügung.

29 KB + die restlichen Felder und Zusatzdaten <= BufferKBSize


Nun kann man BufferKBSize zwar maximal auf 1000 setzen (also ~0,98 MB, wobei diese Grenze in der OH natürlich wiedermal nicht drinsteht).

Aber dennoch kommt bei mir ein Stream (TIFF) mit nur 160 KB einfach nicht an, wärend es eine knapp 800 KB Textdatei schafft.
hatte mich wohl vermessen



Nun die Frage(n):

Warum kommen nicht alle Dateien durch?

Und wieso wirft das blöde DataSnap keine Fehlermeldung, wenn der Stream zu groß ist?


[edit]
Eigentlich dachte ich erst, daß DataSnap mit irgendwelchen Bytes/Bytefolgen in der Binärdatei nicht klarkommt, aber es liegt einfach nur daran, daß Dateien ab genau 64 KB (also >= 64KB) ebenfalls nicht durchkommen.
Also selbst wenn man BufferKBSize bis auf 1000 KB hochsetzen kann, muß ein Stream dennoch kleiner als 64 KB sein.

Piethan 19. Jan 2011 17:26

AW: Datei über DataSnap Verbindung senden
 
Ich würde statt Datasnap direkt auf Indy zugreifen. Ich versende z.B. so einen Stream:

Delphi-Quellcode:
begin
                  sinput:=IOHandler.ReadLn;
                  try
                     memo1.Lines.Add('Lade: '+sinput);
                     dm_vvk.cs_get_user.Params.ParamByName('iuser').AsString:=sinput;
                     dm_vvk.cs_get_user.Open;
                     stream := TMemoryStream.Create;
                     vtable:= TVirtualTable.Create(self);
                     vtable.Assign(dm_vvk.cs_get_user);
                     buf:=nil;
                     vtable.SaveToStream(stream,True);
                     IOHandler.Write(stream,0,true);
                     buf:= nil;
                     vtable.Free;
                     stream.Free;
                  finally

                  end;
Und lese den Stream beim Client so ein:

Delphi-Quellcode:
    stream:= TMemoryStream.Create;
    abuf:= nil;
    IdTCPClient1.IOHandler.WriteLn('3');
    IdTCPClient1.IOHandler.WriteLn(aactuser.username);
    IdTCPClient1.IOHandler.ReadStream(stream);
    Vtuser.LoadFromStream(stream,true);
    Vtuser.Active:=true;
    stream.Clear;
LG
Dirk

himitsu 20. Jan 2011 08:14

AW: Datei über DataSnap Verbindung senden
 
Nja, DataSnap ist halt soooooo cool und new-style, da wollten wir es mal ausprobieren.

Es kann doch nicht sein, daß soein hochbeworbenes Produkt derartig beschränkt und fehleranfällig ist. :?:

Wenn es aber so gedacht ist, dann sollte man wenigstens solche Beschränkungen auch nennen und mit entsprechenden Fehlermeldungen behandeln. :evil:

DSCHUCH 20. Jan 2011 11:36

AW: Datei über DataSnap Verbindung senden
 
ich war auch der meinung das beruht auf indy, oder liege ich da falsch?

himitsu 20. Jan 2011 11:57

AW: Datei über DataSnap Verbindung senden
 
Jupp, irgendwo im Inneren kommt dann Indy und ich glaub ein DataSet war auch irgendwo mit dabei.

himitsu 20. Jan 2011 16:05

AW: Datei über DataSnap Verbindung senden
 
Liste der Anhänge anzeigen (Anzahl: 2)
So, hab mich nun doch nochmal an Emba gewendet.
http://qc.embarcadero.com/wc/qcmain.aspx?d=90995

Ich liebe dieses vor Datenschutz mangelnde Meldesystem, welches den Post löscht und man alle neu schreiben müßte, wenn man nicht schnell genug schreibt, bevor man wieder ausgeloggt wird.
Und wenn sich wer über das größtenteils Goggle-Translate-Englisch beschwert, dann steige ich wieder auf den Babelfish um. :warn:

[add]
noch 'ne kleine Demoanwendung

Code:
Size of Stream (0 = Exit, -1 = basic tests): -1

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 0

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXBytesStream
  Result.Size     = 0 (0)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 100

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXBytesStream
  Result.Size     = 100 (100)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 29000

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXBytesStream
  Result.Size     = 29000 (29000)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 32000

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXStreamReaderStream
  Result.Size     = -1 (32000)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 64000

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXStreamReaderStream
  Result.Size     = -1 (64000)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 1000000

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXStreamReaderStream
  Result.Size     = -1 (1000000)

Size of Stream (0 = Exit, -1 = basic tests):

Code:
Starting TServerContainer1
Press ESC to stop the server

TServerMethods1.SendToServer
  Data.ClassName = TDBXBytesStream
  Data.Size     = 0 (0)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 0

TServerMethods1.SendToServer
  Data.ClassName = TDBXBytesStream
  Data.Size     = 100 (100)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 100

TServerMethods1.SendToServer
  Data.ClassName = TDBXBytesStream
  Data.Size     = 29000 (29000)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 29000

TServerMethods1.SendToServer
  Data.ClassName = TDBXStreamReaderStream
  Data.Size     = -1 (32000)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 32000

TServerMethods1.SendToServer
  Data.ClassName = TDBXStreamReaderStream
  Data.Size     = -1 (64000)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 64000

TServerMethods1.SendToServer
  Data.ClassName = TDBXStreamReaderStream
  Data.Size     = -1 (1000000)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 1000000










und wenn ServerContainerUnit.TServerContainer1.DSTCPServerT ransport1.BufferKBSize auf 1000 gesetzt ist, dann sieht es so aus:
Code:
**************************************************
*** Client ***************************************
**************************************************

Starting TServerContainer1
Press ESC to stop the server

TServerMethods1.SendToServer
  Data.ClassName = TDBXBytesStream
  Data.Size     = 0 (0)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 0

TServerMethods1.SendToServer
  Data.ClassName = TDBXBytesStream
  Data.Size     = 100 (100)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 100

TServerMethods1.SendToServer
  Data.ClassName = TDBXBytesStream
  Data.Size     = 29000 (29000)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 29000

TServerMethods1.SendToServer
  Data.ClassName = TDBXStreamReaderStream
  Data.Size     = -1 (32768)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 32768

TServerMethods1.SendToServer
  Data.ClassName = TDBXStreamReaderStream
  Data.Size     = -1 (65535)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 65535

TServerMethods1.SendToServer
  Data.ClassName = TDBXStreamReaderStream
  Data.Size     = -1 (65536)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 65536

TServerMethods1.SendToServer
  Data.ClassName = TDBXStreamReaderStream
  Data.Size     = -1 (1000000)

TServerMethods1.ReciveFromServer
  Result.ClassName = TMemoryStream
  Result.Size     = 1000000



**************************************************
*** Server ***************************************
**************************************************

Size of Stream (0 = Exit, -1 = basic tests): -1

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 0

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXBytesStream
  Result.Size     = 0 (0)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 100

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXBytesStream
  Result.Size     = 100 (100)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 29000

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXBytesStream
  Result.Size     = 29000 (29000)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 32768

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXBytesStream
  Result.Size     = 32768 (32768)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 65535

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXBytesStream
  Result.Size     = 65535 (65535)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 65536

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXStreamReaderStream
  Result.Size     = -1 (65536)

ServerMethods1Client.SendToServer
  Data.ClassName = TMemoryStream
  Data.Size     = 1000000

ServerMethods1Client.ReciveFromServer
  Result.ClassName = TDBXStreamReaderStream
  Result.Size     = -1 (1000000)

Size of Stream (0 = Exit, -1 = basic tests):

himitsu 21. Jan 2011 14:26

AW: Datei über DataSnap Verbindung senden
 
Gut, das war's.

Hab mich nun mühevoll bis zur entscheidenden Stelle durchgedebuggt.
Delphi-Quellcode:
function TDBXRowBuffer.WriteBytes(const Reader: TDBXStreamReader): Integer;
var
  Count: Integer;
begin
  if (FOff + TDBXFieldHeader.FBigHeaderLength + FMaxInline) > FBufLength then
    Growbuf(TDBXFieldHeader.FBigHeaderLength + FMaxInline);
  Count := Reader.Read(FBuf, FOff + TDBXFieldHeader.FBigHeaderLength, AvailableInline);
  if Count < 1 then
    FBuf[IncrAfter(FOff)] := Byte((TDBXFieldHeader.FTinyField))
  else
  begin
    if Reader.Eos then
      FBuf[FOff] := Byte((TDBXFieldHeader.FBigField))
    else
      FBuf[FOff] := Byte((TDBXFieldHeader.FBigField + TDBXFieldHeader.FPositive));
    FBuf[FOff + 1] := Byte(((Count shr 8) and 255));
    FBuf[FOff + 2] := Byte(((Count) and 255));
    FOff := FOff + Count + TDBXFieldHeader.FBigHeaderLength;
  end;
  Result := Count;
end;
AvailableInline begrenzt den Stream so, daß er in den Übertragungspuffer (BufferKBSize) reinpaßt und daß dieser kleiner als 64 KB ist, da es nur 2 Byte für die Längenangabe gibt.

Heißt also, daß standardmäßig nur ~29 KB und maximal nur 64 KB pro Stream zur Verfügung stehen.

Eine passende Fehlermeldung oder ein Hinweis in der Dokumentation hätte das Ganze bestimmt vereinfacht.




Bleibt jetzt nur die Frage, ob man den Stream nur in kleine Stückchen aufteilen und dieses dann einzeln versenden/abrufen soll, oder ob man den Stream über eine alternative Route verschickt (würde da aber gerne die Datenverbindung vom DataSnap nutzen) :?:


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:31 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