Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Client / Server Dateien senden und empfangen. (https://www.delphipraxis.net/184426-client-server-dateien-senden-und-empfangen.html)

codenoob 25. Mär 2015 22:58

Client / Server Dateien senden und empfangen.
 
Hi,

Ich hab mal eine Frage.

Ich befasse mich seit kurzem mit den Socket Komponenten und dem senden und empfangen von Dateien.

Ich hab mich mit den TClientSocket / TServerSocket und den Indy TidTCPClient / TidTCPServer Komponenten bisschen befasst.
Die Dateien hab ich immer in ein TFileStream geladen und dann mit SendStram versendet.

Was mir dabei aufgefallen ist war das ich mit....

TClientSocket / TServerSocket nur Dateien mit max. 700MB und mit den Indy TidTCPClient / DidTCPServer bis max. 2GB Grösse versenden konnte.
Gibt es da bei den Komponenten ein Limit was die Grösse des Versendens angeht, oder hat das mit dem FileStream zu tun?


Ich habe da schon Codes gefunden der das ganze blockweise macht leider funktioniert das mit Delphi XE2 leider nicht ka. warum.

Delphi-Quellcode:
procedure SendFile(lpFileName: string; Socket1: TClientSocket);
var
  F: file;
  FileInfo: TFileInfo;
  dwFileSize, dwBytesRead: DWORD;
  Buffer: array[0..4096] of Char;
begin
  {$I-}
  AssignFile(F, lpFileName);
  Reset(F, 1);
  dwFileSize := FileSize(F);
  FileInfo.FileName := lpFileName;
  FileInfo.FileSize := dwFileSize;
  Socket1.SendBuffer(FileInfo, SizeOf(FileInfo));
  repeat
    FillChar(Buffer, SizeOf(Buffer), 0);
    BlockRead(F, Buffer, SizeOf(Buffer), dwBytesRead);
    Socket1.SendBuffer(Buffer, dwBytesRead);
  until (dwBytesRead = 0);
  CloseFile(F);
  {$I+}
end;

procedure ReceiveFile(Socket1: TClientSocket);
var
  F: file;
  lpFileName: string;
  FileInfo: TFileInfo;
  dwFileSize, dwBytesRead: DWORD;
  Buffer: array[0..4096] of Char;
begin
  Socket1.ReceiveBuffer(FileInfo, SizeOf(TFileInfo));
  lpFileName := FileInfo.FileName;
  dwFileSize := FileInfo.FileSize;
  {$I-}
  AssignFile(F, lpFileName);
  ReWrite(F, 1);
  repeat
    FillChar(Buffer, SizeOf(Buffer), 0);
    dwBytesRead := Socket1.ReceiveBuffer(Buffer, SizeOf(Buffer));
    BlockWrite(F, Buffer, dwBytesRead);
    Dec(dwFileSize, dwBytesRead);
  until (dwFileSize <= 0);
  CloseFile(F);
  {$I+}
end;
Kann mir da jemand bisschen unter die Arme greifen der sich damit auskennt und mir den richtigen Weg weisen? Bin absoluter Neuling....;-)

Danke schon im Voraus und Lg. CodeNoob

codenoob 26. Mär 2015 20:05

AW: Client / Server Dateien senden und empfangen.
 
Kann mir da echt keiner helfen?

Uwe Raabe 26. Mär 2015 21:33

AW: Client / Server Dateien senden und empfangen.
 
Zitat:

Zitat von codenoob (Beitrag 1294852)
Ich habe da schon Codes gefunden der das ganze blockweise macht leider funktioniert das mit Delphi XE2 leider nicht ka. warum.

Was heißt: funktioniert nicht?

Übrigens: ein
Delphi-Quellcode:
DWORD
kann auch keine Größe über ca. 4GB speichern. Besser für solche Werte
Delphi-Quellcode:
Int64
nehmen.

Dejan Vu 27. Mär 2015 06:47

AW: Client / Server Dateien senden und empfangen.
 
Schau doch mal nach, wie
Delphi-Quellcode:
FileSize(F)
deklariert ist. Es liefert mW einen 'LongInt', was einem 'Integer' entspricht womit sich die 2GB Obergrenze erklären würden (bei D6).

codenoob 1. Apr 2015 00:05

AW: Client / Server Dateien senden und empfangen.
 
Hier Uwe ich habe Dir hier mal meinen Quellcode.

Anhang 42825

Der Client verbindet mit Server aber beim Senden der Datei bleibt der Server hängen und ich habe echt keine Ahnung was ich da falsch gemacht habe.

Liebe Grüsse Tom

Dejan Vu 1. Apr 2015 06:54

AW: Client / Server Dateien senden und empfangen.
 
Wieso hängst Du den Quellcode nicht an deinen Beitrag?

himitsu 1. Apr 2015 07:37

AW: Client / Server Dateien senden und empfangen.
 
Ja, FileSize, Seek und Co. der "alten" Pascal-Funktionen sind nur 32 Bit, aber in der DP verstecken sich notfalls Addons für 64 Bit.
Ein sequentielles Read/Write ist davon aber nicht betroffen und im FreePascal wurde das Problem auch schon behoben.

Und dann gibt es natürlich noch die vielen neueren Stream-Varianten, und man kann sich schon fast fragen, warum sich einige Entwickler dagegen so wehren und warum sie auch noch die Fehlerbehandlung so dermaßen fahrlässig unterdrücken und fehlermeldungen vershrotten (
Delphi-Quellcode:
{$I-}
ohne Behandeln von IOResult) ... da soll sich dann auch keiner Wundern, wenn er nicht weiß, warum es nicht geht.

codenoob 2. Apr 2015 00:12

AW: Client / Server Dateien senden und empfangen.
 
Ich habe jetzt mal die ganzen {$I-} rausgenommen und der Client scheint die datei ohne Fehler zu verschicken.
Leider bekomme ich beim server jetzt ne E/A Fehler 1784 Fehlermeldung.
Was ist das für ne Fehlermeldung? Und was mache ich immer noch falsch?


Hier mein geändertet Quellcode und wie gesagt ich programmiere es in XE2
Anhang 42834


l.g Tom

himitsu 2. Apr 2015 02:56

AW: Client / Server Dateien senden und empfangen.
 
MSDN-Library durchsuchenGetLastError > https://msdn.microsoft.com/de-de/lib.../ms681386.aspx
Zitat:

ERROR_INVALID_USER_BUFFER
1784 (0x6F8)
The supplied user buffer is not valid for the requested operation.
Delphi-Quellcode:
// SendFile
 Reset(F, 1);
try
  ...
  while dwFileSize > 0 do begin
    //FillChar(Buffer, SizeOf(Buffer), 0); // wozu?
    i := Min(dwFileSize, SizeOf(Buffer));
    BlockRead(F, Buffer, i);
    if Socket.SendBuffer(Buffer, i) <> i then
      raise Exception.Create('eine Fehlermeldung');
    Dec(dwFileSize, i);
  end;
finally
  CloseFile(F);
end;

// ReceiveFile
ReWrite(F, 1);
try
  while dwFileSize > 0 do begin
    i := Min(dwFileSize, SizeOf(Buffer));
    if Socket.ReceiveBuffer(Buffer, i) <> i then
      raise Exception.Create('eine Fehlermeldung');
    BlockWrite(F, Buffer, i);
    Dec(dwFileSize, i);
  end;
finally
  CloseFile(F);
end;
Und du solltest dich unbedingt mal mit Fehlerbehandlungen beschäftigen, aber vorallem auch mit dem Resourcenschutz,
denn Resourcenschutzblöcke (Try-Finally) fehlen in deinem Code an jeder Ecke.
Aber wir lieben ja unsere Speicherlecks und offenen Dateihandles, die bis zum Programmende bestehen bleiben.


Da die Funktion SendFile auf Form1 zugreifen muß (also eine der bösesten globalen Variablen), sollte man sich schon gedanken machen, nach dem Warum.
* Entweder FileInfo als Result und der Aufrufer gibt das dann aus (der bessere und vorallem total unabhängige Weg)
* oder der Aufrufer übergibt zumindestens seine Referenz (Parameter TForm1 ins SendFile aufnemen und Self übergeben > nicht zu empfehlen, da dann immer von TForm1 abhängig ist)
* oder die Prozedur als Methode in TForm1 > private aufnehmen


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