Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Probleme beim Versenden von Dateien mit Indy TCPClient (https://www.delphipraxis.net/9489-probleme-beim-versenden-von-dateien-mit-indy-tcpclient.html)

Chris1986 27. Sep 2003 15:25


Probleme beim Versenden von Dateien mit Indy TCPClient
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi,
ich habe ein kleines Client-Programm geschrieben, das einem Server-Programm Dateien schicken kann. (Siehe Anhang).
Leider tritt dabei ein Problem auf. Bei Dateien die größer sind als ca. 220kb bekomme ich vom Debugger folgende Fehlermeldung:

"Im Projekt pSentStream.exe ist eine Exceptionder Klasse EIdSocketError aufgetreten. Meldung: 'Socket-Fehler #10053
Die Software hat den Abbruch der Verbindung verursacht.'.Prozess wurde angehalten. Mit Einzelne Anweisung oder Start fortsetzen"


Weiß jemand wodran das liegt? Ich vermute ein Problem mit dem Buffer. Aber gefunden habe ich den Fehler nicht. :?

Ich hoffe ihr könnt mir helfen
Gruß
Christian

Chris1986 27. Sep 2003 22:24

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hat denn keiner eine Idee? :wall:

Ich bin auch offen für Vorschläge :lol:. Also, wenn jemand weiß wie ich das komplett anders viel besser machen kann, dann nur her mit euren Ideen. :hi:

Für jemanden der Angst vor Viren hat, hier noch eben der Quelltext beider Programme:

Client:
Delphi-Quellcode:
unit mSentStream;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, IdAntiFreezeBase, IdAntiFreeze;

type
  TSentStream = class(TForm)
    IdTCPClient1: TIdTCPClient;
    btDateisenden: TButton;
    OpenDialog1: TOpenDialog;
    edIP: TEdit;
    Label1: TLabel;
    lbPort: TLabel;
    IdAntiFreeze1: TIdAntiFreeze;
    procedure btDateisendenClick(Sender: TObject);
  private
    { Private-Deklarationen }
    procedure Datei_senden;
  public
    { Public-Deklarationen }
  end;

var
  SentStream: TSentStream;

implementation

{$R *.dfm}

//Methode Datei_senden__________________________________________________________
procedure TSentStream.Datei_senden;
var
  fs: TFileStream;
begin
  if not OpenDialog1.Execute then exit;
  with IdTCPClient1 do
  begin
    fs:=TFileStream.Create(OpenDialog1.FileName,fmOpenRead or fmShareDenyWrite);
    Connect;
    if Connected = true
      then WriteLn(OpenDialog1.filename) //Der Filename wird verschickt
      else Showmessage ('nicht verbunden');
    try
      OpenWriteBuffer;
      try
        WriteStream(fs, true, true, 0);
        CloseWriteBuffer;
      except
        CancelWriteBuffer;
        raise;
      end;
    finally
      Disconnect;
      fs.Free;
    end;
  end;
end;
//Ende Methode Datei_senden_____________________________________________________


//Daten-Transfer starten________________________________________________________
procedure TSentStream.btDateisendenClick(Sender: TObject);
begin
  //Der Hostname wird auf das edit-Feld edIP gesetzt
  IdTCPClient1.Host := edIp.text;
  Datei_senden;
end;
//Ende Daten-Transfer starten___________________________________________________

end.
Server:
Delphi-Quellcode:
unit mGetStream;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPServer, StdCtrls;

type
  TGetStream = class(TForm)
    IdTCPServer1: TIdTCPServer;
    SaveDialog1: TSaveDialog;
    btaktivieren: TButton;
    edPfad: TEdit;
    edFilter: TEdit;
    lbFilter: TLabel;
    lbPfad: TLabel;
    edFilename: TEdit;
    lbFilename: TLabel;
    procedure IdTCPServer1Execute(AThread: TIdPeerThread);
    procedure btaktivierenClick(Sender: TObject);
  private
    { Private-Deklarationen }
    function trueFilename (Filename :TFilename) :tFilename;
    function filter (Filename :TFilename) :string;
  public
    { Public-Deklarationen }
  end;

var
  GetStream: TGetStream;

implementation

{$R *.dfm}

//idTCPServer1 OnExecute:_______________________________________________________
procedure TGetStream.IdTCPServer1Execute(AThread: TIdPeerThread);
var
  fs: TFileStream;
  SizeOfIncomingStream: integer;
  Filename :TFilename;
begin
  //######################################
  Filename := Athread.Connection.ReadLn ;
  //trueFilename ist eine Funktion, die aus dem Pfad den Dateinamen filtert
  SaveDialog1.filename := truefilename (Filename);
  //SaveFilter ist eine Methode, um die Endung der Datei zu bestimmen
  SaveDialog1.Filter := filter (Filename);

  edPfad.text := filename;
  edFilename.text := SaveDialog1.Filename;
  edFilter.text := SaveDialog1.Filter;

  //######################################
  //Der SaveDialog wird ausgeführt und die Datei wird gespeichert.
  if not SaveDialog1.Execute then exit;
  fs := TFileStream.Create(SaveDialog1.Filename, fmCreate or fmShareExclusive);
  with AThread.Connection do
    try
      SizeOfIncomingStream := ReadInteger;
      ReadStream(fs, SizeOfIncomingStream);
    finally
      Disconnect;
      fs.Free;
    end;
end;
//Ende IdTCPServer1 OnExecute___________________________________________________


//Funktionen:___________________________________________________________________

//trueFilename ist eine Funktion, die aus dem Pfad den Dateinamen filtert
function TGetStream.trueFilename(Filename :TFilename):tFilename;
var backslash :boolean;
    i :integer;
begin
  i := 0;
  backslash := false;
  //Der Dateiname ohne Pfaangabe wird gefilter
  while backslash= false do
  begin
    if copy (Filename,length (Filename)-i,1) = '\'
      then begin
             trueFilename := copy (Filename,length (Filename)-i+1,i);
             backslash := true
           end
      else i := i+1;
  end;
end;

//Filter ist eine Funktion die im Filename nach der Endung sucht
function TGetStream.Filter (Filename :TFilename) :string;
var dot :boolean;
    i :integer;
begin
  i:= 0;
  dot := false;
  while dot= false do
  begin
    if copy (Filename,length (Filename)-i,1) = '.'
      then begin
             filter := '*.'+copy (Filename,length (Filename)-i+1,i)+
                       '|'+copy (Filename,length (Filename)-i+1,i);
             dot := true
           end
      else i := i+1;
  end;
end;
//Ende der Funktionen___________________________________________________________


//Serverstart:__________________________________________________________________
procedure TGetStream.btaktivierenClick(Sender: TObject);
begin
  if btaktivieren.Caption = 'Server aktivieren'
    then begin
           idtcpServer1.active := true;
           showmessage ('Dienst gestartet');
           btaktivieren.Caption := 'Server deaktivieren'
         end
    else begin
           idtcpServer1.active := false;
           btaktivieren.Caption := 'Server aktivieren'
         end;
end;
//Ende Serverstart______________________________________________________________
end.
Gruß
Christian

DataCool 27. Sep 2003 23:01

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi Chris,

ich sehe in Deiner Vorgehensweise ein paar Probleme !!!

Was soll das Programm den später genau können ?

Warum schickst Du den Kompletten Datei-Pfad mit ?

Der Client kann im Prinzip so bleiben, nur würde ich mir überlegen, ob Du wirklich den kompletten Pfad mitschicken willst/musst.

Zum Server :

Du verwendest die WriteStream-Funktion so, dass die Stream Grösse mitgeschickt wird.

Beim Lesen des Streams versuchst Du selber die Grösse des Streams auszulesen, das must Du gar nicht, das macht die ReadStream-Funktion :

Schreib es mal einfach so : ReadStream(ms);

Das sollte der Grund für Deinen Fehler sein, habe den Fehler früher selbst so gehabt :mrgreen:

Ein weiterer Gedankenfehler ist, dass der Server Multi-Threaded ist und Du in der Execute-Methode einen Modualen Dialog(Save) ausführst.
Was passiert wenn zwei Clients Daten gleichzeitig senden ?
Was passiert, wenn niemand den SaveDialog bestätigt ?
Dann gibt es einen Timeout und dein Progg stürzt ab !!!

Ich kann Dir gern ein paar mehr Tipps geben, habe mich im letzen Jahr sehe intensiv mit Indy beschäftigt, vor allen Dingen mit IdTcpClient u. IdTcpServer

Gruß Data

Chris1986 27. Sep 2003 23:11

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi Datacool
Also, wenn du noch ein paar Tipps für mich hättest wäre das prima. Ich hab nämlich schon viel im Forum gestöbert und bin dabei oft auf die gleichen Probleme gestoßen. (Z.B. "onwork" funktioniert nicht richtig ect.).

Das Programm ist eigentlich mehr so eine Art Übung, um mal zu sehen was man mit den Indys so alles anstellen kann. Der meiste Quelltext ist aus der Code-Library und auf die Funktionen, die den Pfad zerpflücken war ich eigentlich ein bisschen stolz :oops:

Was hast du mit den Indys denn schon alles gemacht? Ich scheitere z.B. auch kläglich an dem Programmieren einer Statusbar, um zu sehen wieviel von der Datei schon empfangen/versendet wurde.

Hast du vielleicht ein kleines Beispiel-Programm für mich, wo du so einen Datentransfer schon sauber gelöst hast?

Edit:
Ich habe gerade mal probiert statt ReadStream(fs, SizeOfIncomingStream) einfach ReadStream(fs) zu benutzen. Leider funktioniert es nicht. Der Savedialog öffnet sich noch, aber wenn ich speichern will gibt es einen Fehler im Server.

Was ich vergessen habe zu erwähnen:
Der Fehler den ich oben beschrieben habe ensteht im Client, wenn ich den Client in Delphi bearbeite.
Starte ich die *.exe ohne Delphi kommt folgender Fehler:
"Socket-Fehler # 10053.
Die Software hat den Abbruch der Verbindung verursacht"


MfG
Christian

DataCool 27. Sep 2003 23:21

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi Chris,

mein Hauptprojekt mit den Indys ist ein neuer Messanger, komplett in Delphi mit Indy !

Es ist ein Chat, telefonieren u. Cam2Cam möglich !

Das ganze ist auch schon online www.telwell.de

Aber ich benutze die Indy-Komponenten z.B. auch bei einer Anwendung im Gastronomie Bereich, wo es eine grosse Cafe-Kette gibt die in über 50 Standorten ein Programm von mir einsetzt, wo jeder eine lokele Firebird Datenbank hat.

Diese 50 Datenbanken der einzelnen Standorte werden per Indy zur Zentrale übertragen und zu einer Main-DB Syncronisiert.

DAmit in der Zentrale Reporting usw. durchgeführt werden können.
Da arbeite ich auch mit einer Fortschrittsanzeige beim Übertragen der DB :mrgreen:

Wo kann ich Dir denn jetzt konkret helfen ?

Data

Chris1986 27. Sep 2003 23:30

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Also,
ich habe oben meinen Thread nochmal editiert.
Kannst du mir vielleicht den Code-Schnipsel zeigen, der die Datenbank verschickt und den Code der sie empfängt? Du wirst ja wahrscheinlich auch eine Datei versenden. Oder versendest du die Tabelle mit Strings? Wahrscheinlich nicht. (Das wäre so meine erste Idee, Daten zu übermitteln :lol: )

Ich will nur wissen wie man sowas sinnvoll angeht und was ich tun muss, um Dateien zu versenden die beliebig groß sind. Ausserdem bin ich durch das Konzept der IdTCPClient Kompo noch nicht so ganz durchgestiegen. Warum braucht man Buffer? Und warum auch noch 2?

Gruß
Christian

DataCool 28. Sep 2003 00:07

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi Chris,

ICQ hast Du nicht oder ? Lad Dir mal mein TelWell runter :mrgreen: Habe Nummer 1011

Wie kommst Du jetzt darauf das man zwei Buffer braucht ?

Dein Code war schon soweit ganz ok, nur denn SaveDialog raus und das ReadInteger weglassen und dann nur readstream verwenden

Schicke Dir morgen mal ein Code Bsp.


Gruß Data

Chris1986 28. Sep 2003 09:08

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
So,
ich bin jetzt online bei TelWell. Meine Nummer: 3831. Nur du bist noch nicht da :lol:

Edit:
Achja, was ich mit den 2Buffern meinte waren die Eigenschaften des idTCPClients im Objektinspektor.
Da steht nämlich "RecvBufferSize" und "SendBufferSize".

Wie meinst du das eigentlich mit der Readstream-Methode?
ICQ hab ich auch: 251840671

Gruß
Christian

ATwardz 1. Okt 2003 13:17

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi,
mich quält ebenfalls das Problem der zu grossen Datenmenge und der nicht funktionierenden
onwork Methode!
Das den Anzeigen wurde ich nicht so recht schlau und der Teil mit der Fortschrittsanzeige
fehlt komplett.

Wäre sehr dankbar wenn die Lösung des Problems nochmals angezeigt wird:ALSO WAS ICH ÄNDERN
MUSS AM BEISPIELCODE!

DANKE @wardz
:wiejetzt:

DataCool 1. Okt 2003 13:27

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi ATwardz,

ich habe für Chris ein kleines Demo geschrieben, wo Client und Server enthalten sind.
Das Programm verschickt Dateien beliebiger Grösse, auf dem Server ist eine Fortschrittsanzeige schon fertig implementiert, beim Client bin ich dazu noch nicht gekommen.

Werde den Quellcode gleich mal hochladen !

Gruß Data

DataCool 1. Okt 2003 15:30

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi Leute,

anbei ein kleines Bsp.

Schaut's auch an und gebt bitte ne Rückmeldung, wenn man was verbessern kann.

Mir schon klar das die Benutzung von TMemoryStream bei größeren Datei Probleme versucht :mrgreen:

Aber das ganze war ja auch mal schnell nebenbei gemacht :wink:

Gruß Data


P.S.: Verwendet wurde D5 mit Indy 9

holidudu 24. Apr 2004 16:45

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hallo Leute...

Ich habe mir den Code von DataCool ein Posting höher herunter geladen. Leider bekomme ich beim start der Client.dpr folgende Meldungen...

http://hilfebullet.de/holi/bild1.jpg

http://hilfebullet.de/holi/bild2.jpg

DataCool sagte er habe es unter D5 mit indy 9 geproggt. Kann es sein, dass mir (D6) irgendetwas fehlt?

Gruss, Holi

DataCool 24. Apr 2004 20:42

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi Holidudu,

kann es sein das Du nicht die aktuellste Version der Indys benutzt ? Aktuell ist gerade 9.0.14 !!Die hab ich auch verwendet !

Download unter : Indy Download

Wenn Du Delphi 6 verwendest, ist zwar Indy mit installiert aber in einer älteren Version.

Gruß Data

holidudu 24. Apr 2004 21:35

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Schön, dass du mir so schnell geantwortet hast. :wink:

Kannst du mir vieleicht noch erklären wie man die Indys updated? Ich bin nämlich noch nicht allzu weit mit Delphi. Bin schon froh, dass ich dieses Forum gefunden habe... :mrgreen:

Edit:
Naja... um ehrlich zu sein bin ich ein schlechter english-interpreter um die eventuellen Install-Anweisungen richtig zu verstehen. :zwinker:

DataCool 24. Apr 2004 21:49

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi,

wie war das den gleich noch mal :gruebel: Angaben ohne Gewähr :mrgreen:

1. Das Indy Package deinstallieren und entfernen.

2. In irgenteinem Unterverzeichnis von Delphi 6 müssen alle Indy-Dateien(Id*.pas und Id*.dcu) gelöscht werden.

3. Danach das neue Indy-Package installieren

Gruß Data

holidudu 24. Apr 2004 22:50

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
hehe... lieb von dir! :drunken:

Ok... das krieg ich auch anderweitig (seltsames Wort) raus. :zwinker:

Aber nun mal was anderes:

Ich habe mir deinen Code mal innig angeschaut. Und nachdem ich selber nun schon über eine Woche mir den Hals nach einer funktionierenden Variante verrengt habe indem ich es selber versucht habe, muss ich angesichts deiner Leistung passen. Es gibt nach meinen google-erkenntnissen keine bessere Beschreibung für das Problem Dateien zu verschicken. Jedenfalls nicht im deutschsprachigen Raum. Mein höchster Respekt davor ist dir sicher! :wink:

Aber mal ne Frage:

Die *.exe Dateien funktionieren ja auch bei mir... auch ohne indy-update.

Aber warum bekommt der Server keine SaveDialog-Abfrage? Ich meine... sowas müsste doch vor dem Senden der Parts geschehen, oder?
Ich kann Dateien versenden mit Statusanzeige auf beiden Seiten. Genial! Nur wie speichere ich das Empfangene... und wo? :freak:

DataCool 24. Apr 2004 23:12

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi,

also wenn Dir meine Arbeit so gefällt, dann zieh Dir www.telwell.de]TelWell Messenger[/URL]
rein, das ist ein Messenger den ich auf Indy Basis geschrieben habe. Meine Nummer da 1011

Aber zu Deiner Fragen :

1. Warum wird kein Save-Dialog verwendet :
Nun der Sinn einer Server-Anwenung ist es ja Multi-Threaded zu Laufen, d.h. das der Server mehere Anfragen auf einmal bearbeiten kann.
Du kannst einen Save-Dialog verwenden, dieser müßte nur syncronisiert aufgerufen werden. Aber die ist absolut gegen den Sinn eines Servers, weil der Server dann auf eine User-Eingabe warten muss und ein Server sollte selbstständig arbeiten.

2. Wie jetzt mit den gesendeten Dateien umgehen ?
Z.B. alle ankommenden Dateien in einem bestimmten Verzeichnis z.B. "Incomeing Files" ablegen. Damit die Dateinamen eindeutig sind kannst Du temporäre generierte Namen verwenden. Entweder über die Windows-Funktion oder durch z.B. "file_"+inttostr(AThread.ThreadID) oder Du schickst den Namen der Datei mit bevor Du den Stream sendest.

3. Ich habe noch ein weiters Bsp. zu dem Thema hier gepostet, weil das erste hier ein Quick-Hack war und ich mit dem Ding nicht wirklich zufrieden war :
http://www.delphipraxis.net/internal...highlight=indy

Gruß Data

holidudu 24. Apr 2004 23:36

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Zitat:

also wenn Dir meine Arbeit so gefällt, dann zieh Dir www.telwell.de]TelWell Messenger[/URL]
rein, das ist ein Messenger den ich auf Indy Basis geschrieben habe. Meine Nummer da 1011
Das lass ich mir bestimmt nicht zweimalsagen... :mrgreen:

Danke erstmal für die tolle Hilfe hier! Ich melde mich dann morgen in aller Frische... :love:

holidudu 26. Apr 2004 19:54

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
@ DataCool

Zitat:

original von DataCool

2. Wie jetzt mit den gesendeten Dateien umgehen ?
Z.B. alle ankommenden Dateien in einem bestimmten Verzeichnis z.B. "Incomeing Files" ablegen. Damit die Dateinamen eindeutig sind kannst Du temporäre generierte Namen verwenden. Entweder über die Windows-Funktion oder durch z.B. "file_"+inttostr(AThread.ThreadID) oder Du schickst den Namen der Datei mit bevor Du den Stream sendest.
Das verstehe ich jetzt nicht ganz... warum sollte es uneindeutige FileNames geben? Der jeweilige Name der Datei wird doch jedesmal mitgeschickt, oder? :stupid:

Aber darum geht es mir eigentlich garnicht in erster Linie... :roll:

An welcher Stelle in deinem code könnte ich z.B. am besten sowas wie einen SaveDialog einbauen? Ich möchte, dass man optional wählen kann ob man das File gezielt auf Platte oder in einem Incoming speichern will. Ich bin deswegen der Meinung, (dass das Sinn macht) weil man das Programm dadurch auch fürs LAN tauglich machen würde. So nach dem Motto: "He Otto... schieb doch mal eben das neueste Moorhuhn rüber!" :arrow: :dancer2:
Und da wäre es praktisch wenn der Server-User das File gezielt ablegen könnte. Nur so als Option, weisst du? :wink:

DataCool 27. Apr 2004 09:45

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Hi Holidudu,

der Sinn und Unsinn des SaveDialogs ist mir schon klar :wink:

Wenn Du gerne dem Benutzer die Möglichkeit zum gezielten Speichern geben möchtest, dann mach es doch ähnlich wie Kazaa und eMule !
Mach Dir ein Verzeichnis Incoming Files ! Dort speichere zuerst die angekommenden Dateien ! In einer Listbox oder einen Listview zeigst Du dem User als empfangene Dateien an, dort kann er Sie dann über einen SaveDialog woanders hin speichern.

Wenn Du damit nur was wie einen FileTransfer wie bei ICQ hinbekommen willst, kannst Du auch mit einen Save-Dialog aus der Server Code raus arbeiten, aber wie vorher schon gesagt, dieser muss dann syncronisiert aufgerufen werden.

Gruß Data

holidudu 27. Apr 2004 15:50

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
Ja danke... die Idee ist gut. Einfach eine Listbox mit allen geladenen Files und darauf eine Umlagerungsmöglichkeit...*patsch*. Hätte eigentlich selbst drauf kommen müssen :roll:

holidudu 28. Apr 2004 19:27

Re: Probleme beim Versenden von Dateien mit Indy TCPClient
 
@DataCool

Ich bin jetzt mal dazu gekommen daran zu arbeiten das File zu speichern. Leider ist mir absolut schleierhaft, warum das nach dem Splitten wieder zusammen gebappte File im Ordner C:\ landet...

Kannst du mir das vieleicht mal erläutern, damit ich überhaupt an sowas wie einen Incoming arbeiten kann? :cyclops:


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:28 Uhr.

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