Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Software-Projekte der Mitglieder (https://www.delphipraxis.net/26-software-projekte-der-mitglieder/)
-   -   Beispiel zum Versenden von Dateien mit Indy (https://www.delphipraxis.net/13169-beispiel-zum-versenden-von-dateien-mit-indy.html)

DataCool 12. Dez 2003 10:54


Beispiel zum Versenden von Dateien mit Indy
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi Leute,

auf vielfachen Wunsch habe ich nochmal ein Beispiel zum Versenden von Dateien mit Indy erstellt.

Das Beispiel enthält Client und Server incl. Sourcecode natürlich.

Desweiteren verfügen Client und Server über eine Progressbar die den Übertragungsstatus anzeigt und eine Anzeige der aktuellen Sendegeschwindigkeit.

Würde mich über ein kleines Feeedback freuen :wink:

Gruß Data

supermuckl 12. Dez 2003 13:13

Re: Beispiel zum Versenden von Dateien mit Indy
 
vielen dank :) ich werde bald ne freeware fileübertragungstool hier zum dl anbieten :>
mit queue und so weiter

thx

edi-design 12. Dez 2003 13:42

Re: Beispiel zum Versenden von Dateien mit Indy
 
vielen dank, jetzt weiß ich wie ich das mit der progressbar machen kann thx

cu andré

ATwardz 14. Dez 2003 22:31

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi,

Endlich mal ein schönes Beispiel! DANKE! :-D
Ich fand heraus das die Splitanzahl bei ca 70 liegen sollte um die beste Geschwindigkeit zu erlangen!
Kann mich auch irren aber Fakt ist(zumindest nach meinen Ergebnissen) das die Paketgrösse mit der Dateigrösse proportional steigen muss, um immer die beste Geschwindigkeit zu erhalten!

Danke nochmals!

@wardz

ATwardz 15. Dez 2003 19:48

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hab da noch ne Frage!

ich hatte so ein Programm vorher schon ohne SPLIT aber da wurden die Datei(3Mb) innerhalb 1 sek verschickt!
Das programm mit Split braucht über ne Minute und arbeitet mit ner Geschwindigkeit von 20 KB\sek!

Ich will es aber zumindest annähernd so schlnell wie mein altes laufen lass!
Ich habe die vermutung, das die bestätigung vom server an den client für jedes Paket das Problem ist! Der hält sich damit zulange auf!
Wie kann ich das umgehn ohne einen DAtenverlust zu erleiden! :roll:

Danke @wardz

DataCool 15. Dez 2003 20:23

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi ATwardz,

wie hast Du den 3 MB pro Sek. verschickt ? Doch wohl nicht übers Internet, wenn doch will ich dieselbe Leitung :mrgreen:

Du hast Deine 3 MB pro Sek. wahrscheinlich erreicht, indem Du die Datei komplett und mit der Verwendung von OpenwriteBuffer und CloseWriteBuffer versendet hast. Was Du dabei vergessen hast ist :

Das bei der Verwendung des WriteBuffers das Ereignis OnWork beim Schreiben in den Buffer schon ausgelöst wird, nicht wenn der Buffer mit CloseBuffer abgeschickt wird.

Gruß Data

ATwardz 17. Dez 2003 14:26

Re: Beispiel zum Versenden von Dateien mit Indy
 
JA, das ist richtig das ich die ganze Datei verschickt habe!
Erreichen kann man 3 MB/sek auch über das INET aber nur wenn eine Verbindung von Router zu Router aufgebaut wird, habe ich hier im Forum gelernt! :lol:

3 MB in unter 3 Sek

kann es sein, das es vielleicht sinn macht die Datei erst zu splitten und auf der Festplatte abzulegen, dann zu senden un der Server die ablegt bis alle vorhanden sin und dann zusammensetzt, dann wäre eine resumfunktion auch recht einfach und übersichtlich!

Ich weiss das der jetztige Code eigentlich sehr ähnlich arbeitet aber irgendwie muss das doch funksten! :cry:

DAnke

@wardz

phlux 17. Dez 2003 14:57

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi DataCool :hi:
Super Beispiel :thumb: hatte vor in der freien Zeit mal son kleines Shareprog zu schreiben ;) da kommt mir dein Bsp ganz recht :)
Nur wenn ich so den Source sehe krieg ichs gruseln :shock: :pale: hast du dir schonmal den Pascal Style Guide angeguckt?? Soll jetzt keine böse kritik sein ;) aber wenn ich Code sehe der mit Tab eingerückt ist schauderts mich gewaltig :?

mfg phlux :hi:

DataCool 17. Dez 2003 21:01

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi Phlux,

was hast Du gegen die einrückung mit Tabs ?
Aber Du hast recht mit den Pascal Style Guides habe ich mich noch nicht beschäftigt *g
Hab ich jetzt was lebensnotwendiges verpasst ?

Die neugier hat mich gerade gepackt und ich hab mal kurz bei Borland reingeschaut, zu 90 % halte ich mich sogar dran und die Stelle mit den Tabs hab ich auch nicht gefunden, außerdem ist das eine Einstellung in Delphi selber in wieviel Leerzeichen ein Tab umgesetzt wird.

Gruß Data

jonny 19. Dez 2003 14:44

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hallo ich habe ein kleines Problem also folgendes.
Wenn ich das Projekt runterlade und ausführe dann funktioniert alles bestens (Ein sehr schönes und gutes Beispiel) wenn ich aber die Projektdateien öffne und neu Compiliere (Delphi 7 Pro) so funktioniert das ganze nicht mehr da ich das Beispiel aber schon in irgendeiner Form verwenden möchte würde ich gerne wissen wo der Fehler ist.

DataCool 19. Dez 2003 15:02

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi,

was bekommst Du beim compilieren den für eine Fehlermeldung ?

Gruß Data

jonny 19. Dez 2003 15:09

Re: Beispiel zum Versenden von Dateien mit Indy
 
Ähh beim Compilieren selbst bekomme ich keine Fehlermeldung es läuft alles super Die Programme lassen sich auch starten nur halt wenn ich den Server Starte und dann vom client aus eine Datei sende so fängt er an zu senden bleibt bei der hälfte stehen (beim Server kommt nichts an er erstellt lädiglich die Datei die ist aber leer) und der server friert ein es tut sich einfach nichts mehr.

DataCool 19. Dez 2003 15:14

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi,

ich würde sagen da hilft nur debuggen !

Welche Indy Version benutzt du denn ?

Wenn du die Exe-Datei aus meinem Projekt direkt startest und die gleiche Datei sendest, geht es dann ?

Gruß Data

jonny 19. Dez 2003 15:32

Re: Beispiel zum Versenden von Dateien mit Indy
 
Ja das funktioniert. Ich habe es erst nicht geglaubt habe deine Version nochmal entpackt und es getestet und es lief habe die Projektdateien dann geöfnet und sofort compiliert ohne etwas zu ändern und dann kam der gleiche Fehler auf wie schon beschrieben.

jonny 19. Dez 2003 15:34

Re: Beispiel zum Versenden von Dateien mit Indy
 
Ich benutze Indy Version 9 die standardmässig bei Delphi 7 Pro dabei ist.

jonny 19. Dez 2003 15:38

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hier hab ich mal die von mir Kompilierten Dateien zum Download Link

DataCool 19. Dez 2003 15:53

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi,

das es die 9ner von Indy isr war mir klar, aber die Versionsnummer dahinter ist auch wichtig, die neuste ist die 14er und Indy 10 ist auch bald(hoff) fertig.

Gruß Data

DataCool 19. Dez 2003 16:00

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi,

hab das ganze mal eben mit Deine Exen getestet und der Fehler tritt auch bei mir auf, da der Fehler bei dir und mir auftritt und bei meiner Exe bei Dir und mir läuft, muss das irgentwie mit Deiner Delphi-Konfiguration zusammen hängen.

Entweder Du hast nicht das neuste Indy(9.014) oder Deine Compiler-Einstellungen sind irgentwie mau *g

Was passiert bei Dir denn, wenn Du Client und Server bei gleichzeitig debuggst ?
Wo tritt ein Fehler oder eine Exception auf und an welcher Stele ?

Gruß Data

jonny 19. Dez 2003 16:21

Re: Beispiel zum Versenden von Dateien mit Indy
 
Also wenn ich den Client Compiliere und den Server nicht läuft das auch umgekehrt kommt die Fehlermeldeung also liegt das ganze schon mal am Server werde gleich Debuggen.

Wie krieg ich die Version von Indy raus?

jonny 19. Dez 2003 16:39

Re: Beispiel zum Versenden von Dateien mit Indy
 
So habe mal mit dem ereignis Protokoll nachgeschaut (Server)

Zitat:

Thread-Start: Thread-ID: 1176. Prozess FileSendServer.exe (880)
Prozessstart: D:\Projekte\FileSend ClientServer\Server\FileSendServer.exe. Basisadresse: $00400000. Prozess FileSendServer.exe (880)
Modul geladen: FileSendServer.exe. Enthält Debug-Infos. Basisadresse: $00400000. Prozess FileSendServer.exe (880)
Modul geladen: ntdll.dll. Ohne Debug-Infos. Basisadresse: $77F40000. Prozess FileSendServer.exe (880)
Modul geladen: KERNEL32.dll. Ohne Debug-Infos. Basisadresse: $77E40000. Prozess FileSendServer.exe (880)
Modul geladen: USER32.dll. Ohne Debug-Infos. Basisadresse: $77D10000. Prozess FileSendServer.exe (880)
Modul geladen: GDI32.dll. Ohne Debug-Infos. Basisadresse: $77C40000. Prozess FileSendServer.exe (880)
Modul geladen: ADVAPI32.dll. Ohne Debug-Infos. Basisadresse: $77DA0000. Prozess FileSendServer.exe (880)
Modul geladen: RPCRT4.dll. Ohne Debug-Infos. Basisadresse: $78000000. Prozess FileSendServer.exe (880)
Modul geladen: OLEAUT32.dll. Ohne Debug-Infos. Basisadresse: $770F0000. Prozess FileSendServer.exe (880)
Modul geladen: msvcrt.dll. Ohne Debug-Infos. Basisadresse: $77BE0000. Prozess FileSendServer.exe (880)
Modul geladen: ole32.dll. Ohne Debug-Infos. Basisadresse: $77180000. Prozess FileSendServer.exe (880)
Modul geladen: VERSION.dll. Ohne Debug-Infos. Basisadresse: $77BD0000. Prozess FileSendServer.exe (880)
Modul geladen: COMCTL32.dll. Ohne Debug-Infos. Basisadresse: $77310000. Prozess FileSendServer.exe (880)
Modul geladen: UxTheme.dll. Ohne Debug-Infos. Basisadresse: $5B0F0000. Prozess FileSendServer.exe (880)
Modul geladen: MSCTF.dll. Ohne Debug-Infos. Basisadresse: $746A0000. Prozess FileSendServer.exe (880)
Modul geladen: nView.dll. Ohne Debug-Infos. Basisadresse: $10000000. Prozess FileSendServer.exe (880)
Modul geladen: SHLWAPI.dll. Ohne Debug-Infos. Basisadresse: $63180000. Prozess FileSendServer.exe (880)
Modul geladen: SHELL32.dll. Ohne Debug-Infos. Basisadresse: $773A0000. Prozess FileSendServer.exe (880)
Modul geladen: PSAPI.DLL. Ohne Debug-Infos. Basisadresse: $76BB0000. Prozess FileSendServer.exe (880)
Modul geladen: WINMM.dll. Ohne Debug-Infos. Basisadresse: $76AF0000. Prozess FileSendServer.exe (880)
Modul geladen: COMCTL32.dll. Ohne Debug-Infos. Basisadresse: $71950000. Prozess FileSendServer.exe (880)
Modul geladen: CTWDM32.dll. Ohne Debug-Infos. Basisadresse: $76AC0000. Prozess FileSendServer.exe (880)
Modul entladen: CTWDM32.dll. Prozess FileSendServer.exe (880)
Modul geladen: UNKNOWN_MODULE_4. Ohne Debug-Infos. Basisadresse: $00B80000. Prozess FileSendServer.exe (880)
Modul geladen: WS2_32.dll. Ohne Debug-Infos. Basisadresse: $00BC0000. Prozess FileSendServer.exe (880)
Modul geladen: WS2HELP.dll. Ohne Debug-Infos. Basisadresse: $00BE0000. Prozess FileSendServer.exe (880)
Modul geladen: nvwddi.dll. Ohne Debug-Infos. Basisadresse: $00BF0000. Prozess FileSendServer.exe (880)
Modul geladen: MSWSOCK.dll. Ohne Debug-Infos. Basisadresse: $00C90000. Prozess FileSendServer.exe (880)
Modul geladen: WSHTCPIP.dll. Ohne Debug-Infos. Basisadresse: $00CD0000. Prozess FileSendServer.exe (880)
Thread-Start: Thread-ID: 1052. Prozess FileSendServer.exe (880)
Thread-Start: Thread-ID: 3356. Prozess FileSendServer.exe (880)

jonny 20. Dez 2003 11:48

Re: Beispiel zum Versenden von Dateien mit Indy
 
Wenn es jemanden hilft um mir helfen zu können

20KB werden übertragen und dann friert das ganze erst ein. Habe es mit mehreren Dateien ausprobiert die Ziel Datei ist immer nur 20KB groß

bitte weiter um Hilfe.

jonny 22. Dez 2003 14:26

Re: Beispiel zum Versenden von Dateien mit Indy
 
Ich bitte um Hilfe es ist sehr Wichtig das das bei mit auch funktioniert.
Bitte, Bitte, Bitte helft mir doch.

DataCool 22. Dez 2003 15:03

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi Jonny,

ich hab nur D5, sorry !!

DA muss sich wohl jemand anderes erbahmen !

Gruß Data

jonny 22. Dez 2003 15:45

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hallo hat hier denn niemand Delphi 7 Pro der das Programm für mich testen könnte und mir dann helfen könnte? Bitte!!!!

ATwardz 22. Dez 2003 22:43

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi,

ich habe Delphi 7 pro und habe das selbe Problem, habe das Bsp auch genutzt!
Bemerkt habe ich es alledings erst als ich eure Beiträge gelesen habe da ich die Projektdatei nie ausgeführt habe! Ich habe den Code nur als Hilfe für mein eigenes Projekt verwendet!
Fakt ist:
- Delphi 7 pro bau misst, nicht nur bei dir!

um das Problem jedoch zu lösen, musst du lediglich den Code in eine neue Unit kopieren und die entsprechenden Kompos hinzufügen, voila es funkst, zumindest bei mir!

Probier mal sonst kannste auch meinen code als Bsp haben!

@wardz

jonny 22. Dez 2003 23:42

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hm leider tut das auch nicht wenn ich das einfach so reinkopiere. Es wäre sehr nett wenn du mir deinen Code zurverfügung stellen würdest.

Bin jetzt schon Dankbar und hoffe das der funktioniert.

jonny 27. Dez 2003 18:50

Re: Beispiel zum Versenden von Dateien mit Indy
 
Ich will hier ja keinen hetzen aber ich würde den Code von ATwardz doch noch haben wollen.

Ist nicht bös gemeint aber ich brauche den wirklich dringend.

negaH 6. Jan 2004 02:43

Re: Beispiel zum Versenden von Dateien mit Indy
 
Ich verstehe nicht warum ihr nicht die Datei im ganzen in einem Rutsch senden wollt. Beim TCP/IP kann es zu keiner Datenverfälschung kommen und die Datenpackete treffen in der gleichen Reihenfolge ein wie sie vesendet wurden. Das bedeutet das man vom Server zum Clienten einen Header der den Dateinamen + Dateigröße und einen Datenblock der die Datei als ganzen enthält in einem Rutsch sendet. Wenn man unbedingt eine Überprüfung möchte so kann man hinter die Daten eine Prüfsumme anhängen. Der einzigste Fehler der auftreten kann ist ein Abbruch der Verbindung. Es wäre also hilfreich wenn der Client bei der Download-Anforderung eine Datei dort weiterladen kann wo abgebrochen wurde. Aber mehr müsste man eigentlich nicht berücksichtigen.
Wenn ihr eine Progressbar wollt dan geht auch dieses einfach. Nachdem der Header empfang en wurde wissen wir ja die Dateigröße der Daten die noch folgen. Also ließt man aus dem Socket nun Happen von 1024 Bytes und updatet die Progressbar. Allerdings beim INDY müsst ihr immer bedenken das JEDE Client/Server Conection im .Execute() in einem eigenen Thread läuft. Das heist beim Updaten der Gauge muß dies Threadfest sein.
Übrigens, beim TCP/IP Protokoll ist es nicht zwingend das die Daten als TEXTE oder Textkommandos übertragen werden. Man kann auch einfach binäre Daten übertragen. Statt also einen aufwendigen Kommando-Text-Parser zu coden würde ein einzigstes Byte als Kommando/Response Code schon ausreichen.

Gruß Hagen

jonny 6. Jan 2004 02:51

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hast du denn ein Gutes Beispiel dafür? Bin nicht gerade Fit auf dem Gebiet "Indy".

Mir ist aufjedenfall Wichtig das der Server Mehrere Dateien Gleichzeitig empfangen kann und das er auch den (Download)-Status der dateien anzeigen kann und weiter ist mir wichtig das auch der Client den (Upload)-Status anzeigen kann also mit einer Progressbar oder so.

negaH 6. Jan 2004 07:14

Re: Beispiel zum Versenden von Dateien mit Indy
 
Ein konkretes Beispiel habe ich nicht, aber wie können es Step by Step durchgehen.

Zuerst bauen wir den Server und erklären dabei das benutzte Protokoll.
Als erstes definieren wir was als wichtigstes und erstes in das projekt integeriert werden soll. Wir beschränken uns erstmal auf das Notwendigste, also keine Progressbar und nur Upload von Dateien vom Clienten aus den Server.

Erzeuge neues Project und nenne es Server. Auf's Hauptformular bringste einen INDY TCP/IP Server drauf. Bei diesem stellste folgendes ein:

.Bindings := 0.0.0.0:7000;
.DefaultPort := 7000;
.ReuseSockects := rsTrue;
.Active := True;

Zusätzlich ein TMemo mit Namen Memo1 und folgenden Eigenschaften:

.Font := 'Courier New';
.Align := alClient;
.Lines := '';
.WordWrap := False;
.Scrollbars := ssBoth;

Nun im OI in das Ereigniss .OnExecute ein Doppelklick. Wir landen im Sourceeditor und coden NUR diese eine Execute Methode, denn mehr benötigen wir erstmal garnicht.

Damit klarer wird was wir möchten definieren wir aber erstmal unser Protokoll.
Jede Kommunikation beginnt mit einem Kommando-Byte, somit stehen uns maximal 256 verschiedene Kommandos zur Verfügung. Per Definition legen wir folgende Kommandos fest:

0= NULL, heist keine Aktion und dient als Dummy Message um eventuell connections am leben zu erhalten
1= LOGIN, der Client sendet dieses Kommando IMMER als erstes, über dieses Kommando identifiziert sich ein Client und die Clientsoftware. Ein Server antwortet NUR auf eine solches korrektes Client Login. D.h. dieses Kommando MUSS das erste sein was der Server empfängt. Falls dies nicht der Fall ist trennt der Server sofort die Conection.
3= ERROR, Fehlerpacket
4= LOGOUT, der Client trennt die verbindung
5= UPLOAD, der Client sendet eine Datei, direkt nach dem Kommando-Byte folgen der dateiheader und die eigentliche Datei

Der Server hat auf jedes Kommando mit einem Echo-Kommando zu bestätigen. D.h. wenn der Client das Kommando=1=LOGIN sendet antwortet der Server ebenfalls mit Kommando=1=Login bei Erfolg oder er antwortet mit Kommand=3=ERROR und trennt die Verbindung.

Genauer werden wir erstmal das Protokoll nicht beschreiben, die Sourcen sollten es erklären. Nun der Code in OnExecute() sollte so aussehen:


Delphi-Quellcode:
var
  LastSessionID: Integer = 1;

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
  SessionID: Integer;

  procedure DoLog(const Msg: String);
  var
    S: String;
    I: Integer;
  begin
    S := Format('%s-%0.6d: %s', [FormatDateTime('YYMMDD HHNNSS ZZZ', Now), SessionID, Msg]);
    for I := 1 to Length(S) do
      if S[I] in [#10,#13] then S[I] := ' ';
  // da Memo1.Lines.Add() intern über SendMessage() arbeitet sollte dies Threadsafe sein.
    Memo1.Lines.Add(S);
  end;

  function ReadByte: Byte;
  begin
    AThread.Connection.ReadBuffer(Result, SizeOf(Result));
  end;

  function ReadLong: Cardinal;

    function SwapLong(Value: Cardinal): Cardinal;
    // konvertiert Big Endian zu Little Endian
    // im INet ist es üblich ALLE Daten in Big Endian zu übertragen
    asm
      BSWAP EAX
    end;

  begin
    AThread.Connection.ReadBuffer(Result, SizeOf(Result));
    Result := SwapLong(Result);
  end;

  function ReadString: String;
  begin
    SetLength(Result, ReadByte);
    AThread.Connection.ReadBuffer(Result[1], Length(Result));
  end;

  procedure WriteByte(Value: Byte);
  begin
    AThread.Connection.WriteBuffer(Value, SizeOf(Value));
  end;

  procedure WriteString(const Value: ShortString);
  begin
    WriteByte(Length(Value));
    AThread.Connection.WriteBuffer(Value[1], Length(Value));
  end;

var
  FileName: String;
  FileSize: Cardinal;
  FileStream: TStream;
begin
  SessionID := LastSessionID;
  Inc(LastSessionID);

  try
    DoLog(Format('Client connect at IP ', [AThread.Connection.Socket.Binding.PeerIP]));
    if (ReadByte = 1) and (ReadString = 'MyUpload 1.0') then // LOGIN
    begin
// Client hat sich korrekt identifiziert sende Bestätigung und warte auf Kommandos
      WriteByte(1);
      while True do
        case ReadByte of
          0: begin // NULL
               WriteByte(0);
             end;
          2: begin // LOGOUT
               DoLog('Client logout');
               Break;
             end;
          3: begin // ERROR
               DoLog(Format('Client error %d, %s', [ReadByte, ReadString]));
               Break;     // Fehler fürht IMMER zum Abbau der Verbindung
             end;
          4: begin // UPLOAD
               FileName := ExtractFilePath(ParamStr(0)) + 'Upload\' + ReadString;
               FileSize := ReadLong;
               DoLog(Format('Client upload %5d, %s', [FileSize, FileName]));
               try
                 FileStream := TFileStream.Create(FileName, fmCreate);
                 try
                   AThread.Connection.ReadStream(FileStream, FileSize);
                 finally
                   FileStream.Free;
                 end;
                 WriteByte(4);
               except
                 on E: Exception do
                 begin
                   WriteByte(3); // ERROR
                   WriteByte(1);
                   WriteString(E.Message);
                   Break;
                 end;
               end;
             end;
        else
          begin // Invalid Code;
            DoLog('Client sends unknown command, terminate');
            WriteByte(3);
            WriteByte(0); // Errorcode
            WriteString('unknown kommand');
            Sleep(1);
            Break;
          end;
        end;
    end; // falsches/fehlendens Client-Login, trenne einfach die Verbindung, Server ist im Stealth mode
  finally
    DoLog('Client terminated');
    try
      Sleep(1);
      AThread.Connection.Disconnect;
    except
    end;
  end;
end;
Fertig ist der Server. Er sollte KEINERLEI Progressbars besitzen, da Server normalerweise unsichtbar im Hintergund laufen sollten.


Nun ein zweites neues Projekt für den Clienten erzeugen. Auf das Formular ein TidTCPClient mit Namen 'TCP' daruf und Eigenschaften:

.Host := 'localhost';
.Port := 7000;
.ReadTimeout := 5000;

Zusätzlich noch einen TButton, TLabel, TProgressbar und TOpenDialog drauf.
Im OnClick von Button1 steht dann folgendes:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);

  procedure WriteByte(Value: Byte);
  begin
    TCP.WriteBuffer(Value, SizeOf(Value));
  end;

  procedure WriteLong(Value: Cardinal);

    function SwapLong(Value: Cardinal): Cardinal;
    asm
       BSWAP EAX
    end;

  begin
    Value := SwapLong(Value);
    TCP.WriteBuffer(Value, SizeOf(Value));
  end;

  procedure WriteString(const Value: String);
  begin
    WriteByte(Length(Value));
    TCP.WriteBuffer(Value[1], Length(Value));
  end;

  function ReadByte: Byte;
  begin
    TCP.ReadBuffer(Result, SizeOf(Result));
  end;

  function ReadString: String;
  begin
    SetLength(Result, ReadByte);
    TCP.ReadBuffer(Result[1], Length(Result));
  end;

var
  I: Integer;
  SendSize,FileSize: Integer;
  FileName: String;
  FileStream: TStream;
begin
  if OpenDialog1.InitialDir = '' then
    OpenDialog1.InitialDir := ExtractFilePath(ParamStr(0));
  if OpenDialog1.Execute then
  try
    try
      TCP.Connect;
      WriteByte(1);
      WriteString('MyUpload 1.0');
      case ReadByte of
        1: begin
             for I := 0 to OpenDialog1.Files.Count -1 do
             try
               FileName := OpenDialog1.Files[I];
               FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
               try
                 FileSize := FileStream.Size;

                 WriteByte(4);
                 WriteString(ExtractFileName(FileName));
                 WriteLong(FileSize);

                 Label1.Caption := Format('sende %s', [Filename]);
                 Label1.Update;
                 ProgressBar1.Min := 0;
                 ProgressBar1.Max := FileSize;
                 ProgressBar1.Position := 0;

                 while FileSize > 0 do
                 begin
                   SendSize := FileSize;
                   if SendSize > 1024 then SendSize := 1024;
                   Dec(FileSize, SendSize);
                   TCP.WriteStream(FileStream, False, False, SendSize);
                   ProgressBar1.Position := ProgressBar1.Position + SendSize;
                 end;
               finally
                 FileStream.Free;
               end;
               case ReadByte of
                 3: begin // fehler
                      ShowMessage(Format('Fehler %5d, %s', [ReadByte, ReadString]));
                      Break;
                    end;
                 4: ; // alles Ok
               end;
             except
               on E: Exception do
                 ShowMessage(E.Message);
             end;
             WriteByte(2);
           end;
        3: begin
             ShowMessage(Format('Error %d, %s', [ReadByte, ReadString]));
           end;
      else
        ShowMessage('Invalid Responsecode');    
      end;
    finally
      TCP.Disconnect;
    end;
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;
Gruß Hagen

jonny 6. Jan 2004 10:15

Re: Beispiel zum Versenden von Dateien mit Indy
 
Also soweit so gut habe es soweit denke ich verstanden es gab nur einen kleinen Fehler

habe aber die Zeile
Code:
.Bindings := 0.0.0.0:7000;
in
Code:
.Bindings := 127.0.0.1:7000;
geändert und dann hat es funktioniert.

Bin schon gespannt wie es weiter geht!!!


Danke übrigens es ist wirklich nett das du mir hilfst.

negaH 6. Jan 2004 17:59

Re: Beispiel zum Versenden von Dateien mit Indy
 
Bindings mit 0.0.0.0:x sollten eigentlich auch funktionieren, beim mir geht das.

Nun, wie geht es weiter ? Ehrlich gesagt ich weiß es nicht da es ja DEIN Projekt ist :) D.h. es hängt von dir ab wie es weitergeht, den Kern habe ich dir ja gezeit, und so schwierig war's ja dann doch nicht.
Möchtest du zB. im Server ebenfalls eine Progressbar (was ich nicht empfehle) musst du bedenken das ein Server sehr viele Clients zur gleichen Zeit in verschiedenen Threads bedienen wird. D.h. eigentlich müsste für jeden Aufruf des OnExecute() Ereignisses eine eigene ProgressBar her. Beachte, .OnExecute() wird bei INDY in einem eigenen Thread aufgerufen. D.h. für jeden Client der mit dem Server verbindet spaltet TidTCPServer einen eigenes Thread Object ab. Diese ruft dann in SEINEM TThread.Execute; eben das Event TidTCPServer.OnExecute() auf.

Du kannst die Funkionalität erweitern um die Fähigkeit eines Downloads eienr Datei auf Clientseite. Dazu muß der Client erstmal wissen was er downloaden kann. D.h. eine neues Kommando muß her das ein Listing der Dateien abfragt. Dann ein Kommando zum Download einer Datei.

Schwieriger wird es dann aber schon einen interupted/delayed/multiple Download/Upload zu programmieren. In diesem Falle MUSS der Datenbereich der Dateiübertragung Häppchenweise erfolgen. Denn nur so kann der Client/Server mitbekommen wieviele Daten schon übertragen wurde. Man könnte aber auch bei meinem ursprünglichen Konzept bleiben. Dann müsste sich der Client aber erneut nach einem Abbruch ver Verbindung beim Server einloggen. Danach fragt er den Dateistatus der abgerbochenen Datei ab, und überträgt nur den Rest.

Gruß Hagen

jonny 6. Jan 2004 18:42

Re: Beispiel zum Versenden von Dateien mit Indy
 
Also es soll mal ein kleiner Chat werden in dem man die möglichkeit hat dateien zu schicken also gibt es nicht so viele verbindungen zum server und ich würde dann auch son ganz gerne die ProgressBar im Server einbauen. wie mache ich dass denn das der server eine Art Panel auf dem die ProgressBar liegt mit Label wo der Dateiname angezeigt wird erstellt und diesen nach den Upload destroyed. Ich meine er muss ja irgendwie wissen welche jetzt fertig ist und welche zerstört werden muss. Die anderen die evtl dahinter liegen müssen nachrücken damit es optisch schöner ist. Also ich stelle mir das doch sehr kompliziert vor.

jonny 8. Jan 2004 00:02

Re: Beispiel zum Versenden von Dateien mit Indy
 
Also wenn ich beim TCPServer die Eigenschaft "Reuse Socket" auf rsOSDependet stelle dann kann ich auch unter "Bindings" 0.0.0.0:7000 einstellen ansonsten kann ich nur an mich selber dateien schicken.

ATwardz 15. Jan 2004 15:32

Re: Beispiel zum Versenden von Dateien mit Indy
 
Liste der Anhänge anzeigen (Anzahl: 1)
Sorry das ich so lange gebraucht habe aber ich war in den Ferien weg und dann hat die Telekom mir noch das Inet abgeschaltet! :-(
Hab den Anbieter gewechselt!

Wennn es dir noch hilft hier mein Prog!

DevilsCamp 26. Aug 2004 12:37

Re: Beispiel zum Versenden von Dateien mit Indy
 
Liste der Anhänge anzeigen (Anzahl: 1)
*aufwärm*

Hallo.

Ich habe die Files von ATwardz gezogen um sie mir genauer anzuschauen.
Anschließend habe ich ich Programm geschrieben, das gleichzeitig als Client und Server dient, da ich ein kleines, ICQ-ähnliches Programm enwerfen will, mit dem man auch Dateien versenden können soll.

Ich habe folgenden Aufbau:

Formular1 (Main-Form):
GroupBox1 mit 2 TEdits für IP und Port eines Datei-Empfängers und einem Senden Button1
GroupBox2 mit 2 TEdits um Listen-IP und Listen-Port der TIdTCPServer-Komponente einzurichten und einer Mach-Aktiv-Checkbox.


Formular2 (Fortschritts-Anzeige):
Labels für Namen der Datei, Größe, übermittelte Bytes und Gauge für Fortschrittsanzeige.

Formular2 wird z.Z. gleich beim Start des Programms erstellt (warum erklär ich später, siehe **), aber erst angezeigt, wenn ein Transfer stattfindet (mit Formular2.Show). Nach dem Fransfer wird das Formular mit Formular2.Hide wieder ausgeblendet.

Wenn ich nun von PC1 eine Datei zu PC2 sende, dann öffnet sich bei beiden PCs wie erwartet das Transfer-Fenster und wird auch nach dem Transfer wieder ausgeblendet.
Schliesse ich aber nun auf dem Empfänger-PC das Programm, dann bekomme ich eine Fehlermeldung und der PC verliert stark an Performance (der greift ständig auf die Platte zu).

Ich habe schon alles überprüft, aber ich finde keine Lösung zu dem Problem.
Wenn jemand den Quell-Text braucht, so gebe ich ihn gerne an...



**
Wenn ich das Formular2 innerhalb der Receiver-Unit erstellen lasse (in der Create-Anweisung), dann hängt sich das Programm komplett auf, wenn es in der Synchronize-Methode versucht ein Label des Formulars zu verändern...

cgimda 26. Jan 2005 13:09

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hallo ich das gleiche Problem wie jonny.
Wenn ich das Projekt runterlade und ausführe dann funktioniert alles bestens, wenn ich aber die Projektdateien öffne und neu Compiliere (Delphi 7 Pro) so funktioniert das ganze nicht mehr.

Ich habe herausgefnunden an was es liegt, konnte aber das Problem nicht lösen.

Das Problem liegt in folgender Funktion:

Delphi-Quellcode:
function TFileReceiver.Start : Boolean;
Var bError : Boolean;
      bReady : Boolean;
      fs    : TFileStream;
begin
   result := true;
   if iFileSize > 0 then begin
      // Alle Startwerte setzen
      bError := false;
      bReady := false;
      iReceivedBytes := 0;
      // erstmal versuchen die Datei zu erstellen
      // das Zielverzeichnis wo die Daten gespeichert werden sollen könnt Ihr nachher selber bestimmen
      sFileName := 'C:\'+sFileName;
      try
         fs := TFileStream.Create(sFileName,fmCreate or fmShareExclusive);
      except
         // Fehler beim Erstellen der Datei aufgetreten
         result := false;
         exit;
      end;
      try
         // Solange keine Abbruch Bediengung erreicht ist Stream-Pakete lesen
         While (not AThread.Terminated) and (AThread.Connection.Connected) and
                  (not bError) and (not bReady) do begin
            // Buffer(Speicher-Stream) leeren
            tmpMS.clear;
            try
               // versuchen Stream zu Lesen
               AThread.Connection.ReadStream(tmpMS);
               // Steht jetzt auch wirklich was im Stream drin
               if tmpMS.Size > 0 then begin
                  // die gelesenen Bytes jetzt direkt in den FileStream schreiben
                  fs.copyFrom(tmpMS,0);
                  // Anzahl der gelesenen Bytes erhöhen
                  iReceivedBytes := iReceivedBytes + tmpMS.Size;
                  // jetzt durch den Thread die Methode UpdateProgress ausführen
                  // dieses muss mit Syncronize gemacht werden, mehr dazu in Delphi Hilfe
                  AThread.Synchronize(UpdateProgress);
               end;
               bReady := (fs.Size = iFileSize);
            except
               // Fehler beim Lesen des Stream aufgetreten, Speicher leeren
               tmpMS.Clear;
               // Vorgang abbrechen
               bError := true;
            end;
         end;
      finally
         fs.free;
         if bError then
            DeleteFile(sFileName);
      end;
      result := FileExists(sFileName);
   end;
end;
Genauer gesagt liegt es an dieser Zeile:

Delphi-Quellcode:
// jetzt durch den Thread die Methode UpdateProgress ausführen
// dieses muss mit Syncronize gemacht werden, mehr dazu in Delphi Hilfe
AThread.Synchronize(UpdateProgress);
Wenn ich also "AThread.Synchronize(UpdateProgress);" aus der Funktion herausnehme funktioniert das Programm wieder. Leider ist dann die ProgressBar nicht mehr verfügbar.

Wenn ich also während des Empfangen, irgendetwas versuche anzuzeigen bleibt das Programm hängen. Und Wenn es nur ein "Refresh" ist.

Kann mir jemand sagen warum das bei Delphi 7 so ist? DataCool hat es mit Delphi 5 programmiert und es hat funktioniert. Hat jemand eine Lösung für das Problem?

Rastaman 1. Feb 2005 13:26

Re: Beispiel zum Versenden von Dateien mit Indy
 
Wie funktioniert denn das empfangen von Streams mit den Sockets aus Delphi 6?

DataCool 1. Feb 2005 14:55

Re: Beispiel zum Versenden von Dateien mit Indy
 
Hi Gerrit89,

für Delphi6 kannst Du einfach mein Beispiel verwenden.
Bei Fragen einfach melden.

mfg DataCool

Rastaman 2. Feb 2005 17:24

Re: Beispiel zum Versenden von Dateien mit Indy
 
ja aber es gibt die drei komponenten nicht. Server, Client und antifreeze. Ich brauche das ganze mit den Clientsockets.
Hab nur Personal


<-------


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:11 Uhr.
Seite 1 von 2  1 2      

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