Autor Beitrag
GlobalImpact
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Fr 28.07.06 13:35 
Hallo,
ich würde gerne ein Programm schreiben, das Dateien per UDP versenden kann, ich habe mich schon durch alle möglichen Foren gewühlt und oft gelesen, dass UDP nicht unbedingt sinvoll ist zum Versenden von Dateien, ich würde es jedoch nur für mp3s nutzen, d.h. es stört nicht, wenn ein paar KB verloren gehen.

Ich hab das ganze mal mit Indy angefangen:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WinSock, UdpSockUtil, IdUDPServer, IdBaseComponent,
  IdComponent, IdUDPBase, IdUDPClient, IDSocketHandle, IdGlobal, IDStream;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Server: TIdUDPServer;
    Client: TIdUDPClient;
    procedure ServerUDPRead(Sender: TObject; AData: TStream;
      ABinding: TIdSocketHandle);

    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);

      const


  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  zaehler : integer;
implementation

{$R *.dfm}







procedure TForm1.FormCreate(Sender: TObject);
begin
Server.Active := true;
Client.Active := true;
end;

//senden
procedure TForm1.Button1Click(Sender: TObject);

var Buffer : Array [0..4096of Byte;
    Stream : TMemorystream;
begin

Stream := TMemorystream.Create;
Stream.LoadFromFile('D:\bild.jpg');
Stream.ReadBuffer(Buffer, sizeof(Buffer));
Client.SendBuffer(Buffer,sizeof(Buffer));


Stream.free;
end;


// Empfangen am Server und Schreiben in eine Datei.
procedure TForm1.ServerUDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);


var MStream : TMemorystream;
  

begin

MStream := TMemorystream.create;


MStream.LoadFromStream(ADATA) ;
//MStream.Position := MStream.Position + 4096;    *  Hatte mir vorgestallt, dass der Stream einfach um die Größe des Puffers weiterwandert und so bei jedem Klick ein Stückchen mehr von dem Bild übertragen wird
Mstream.SaveToFile('D:\bild02.jpg');

end;

end.



Mein Problem an der Sache ist jetzt, dass das senden zwar funktioniert, aber dass immer nur (logischerweise) der Inhalt des Puffers versendet wird und ich dann immer nur 4KB von der Datei übertrage, d.h. beim Bild nur ein ca. achtel sichtbar ist.

Wie kann ich jetz stückchenweise das Bild übertragen und dann beim Empfänger zusammenfügen?

Danke für die Info

mfg

Global Impact

PS: Hab Indy 9

Moderiert von user profile iconraziel: Code- durch Delphi-Tags ersetzt
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 28.07.06 15:38 
Moin!

Vorab: Bitte verwende die Delphi-Tags für den Code, damit das Syntaxhighlighting aktiv ist. ;)

Jetzt zu deinem Problem(en). ;) Was du dir da ausgesucht hast, ist gar nicht so einfach... :?

Kannst du denn Dateien über eine TCP-Verbindung übertragen? Wenn du das noch nie gemacht hast, solltest du erst mal damit "üben", damit dir die grundsätzliche Vorgehensweise beim Dateitransfer wirklich klar ist. Bei UDP kommen nämlich noch eine ganze Menge weiterer Probleme auf dich zu... :|

Was du beachten mußt:
- UDP hat eine Maximalgröße für Datagramme (Pakete), die bei 512 Bytes liegt. Übergibst du der Sender-API mehr, stückelt die das schon auf... (was nicht immer so besonders sinnvoll ist)
- UDP-Pakete können einfach auf dem Weg verloren gehen, du merkst nichts davon
- Die Empfangsreihenfolge ist nicht zwingend die gleiche, wie beim Senden! :shock: :!:
- Wenn du auf Datenkonsistenz angewiesen bist (Dateitransfer), dann mußt du für eine Sicherungsschicht sorgen (nachhalten, welche Pakete in welche Reihenfolge gehören und fehlende nachfordern -> schau mal nach "Sliding-Window-Protokoll")
- Wenn du streamen willst, was als fehlertolerant definiert ist, dann brauchst du keine Sicherungsschicht, mußt aber mit "Löchern" im Datenstrom umgehen können.

Die Frage ist also: was genau willst du denn eigentlich machen?!

Wenn du dir über all die genannten Dinge ein paar Gedanken gemacht hast, dann kannste ja nochmal nachfragen, wenn du ein konkretes Code-Problem hast. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
GlobalImpact Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Fr 28.07.06 16:00 
Erstmal Danke für die Antwort.

Ich habe mich vorher schon über die Eigenschaften von UDP, was die Fehler betrifft (Datenpakete werden in anderer Reihenfolge gesendet...), schlau gemacht, hab halt in diesem und anderen Foren Tutorials und Beiträge gelesen und möchte selbst gerne ausprobieren, wie das ganze mit UDP funktioniert.

Ich habe schon ein Programm geschrieben, mit dem Dateien über TCP übertragen werden (TIDTCPSockets von Indy verwendet). Da konnte ich die Dateien leicht via sendstream verschicken.
Die Schwierigkeit, die ich jetz bei UDP habe, ist, dass ich die Datei über einen Puffer verschicken muss.

Toll wäre natürlich, wenn jemand ein Tutorial zu dem Thema wüsste (Ich habe bereits ein UDP Tutorial gefunden, das beschäftigt sich aber nur mit dem senden von Text, was mir nicht weiterhilft, einen Chat über UDP habe ich bereits bewerkstelligt).

Ich bin Dankbar für jede Info, die ich über die UDP Indys und Sendbuffer kriege.

Vielleicht kann mir ja irgendjemand weiterhelfen.

Danke nochmal

mfg

Global Impact
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 28.07.06 16:37 
Moin!

user profile iconGlobalImpact hat folgendes geschrieben:
Ich bin Dankbar für jede Info, die ich über die UDP Indys und Sendbuffer kriege.

Was ist denn konkret dein Problem damit? :gruebel: Wie .SendBuffer funktioniert, sollte dir klar sein, wenn du es schon mit einer TCP-Verbindung geschafft hast.

IMHO liegt dein Problem nicht beim Umgang mit den Indies, sondern beim Programmkonzept... ;) Du kannst halt per UDP immer 512 Bytes am Stück versenden, Streams direkt zu verwenden, kannste vergessen (weil keine Protokoll-Infos drin sind), fertig.

Also, wo ist genau das Problem bei dir? :nixweiss:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
GlobalImpact Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Fr 28.07.06 17:08 
Mein Problem is, dass ich bei meinem TCP Programm die Dateien im ganzen verschicken konnte, bei den UDP Sockets aber über sendbuffer schicken muss.

Ich schaffs ja mit Sendbuffer Daten zu senden, ich kann halt nur nicht 5 MB oder sowas in einen Puffer schicken, weil scheinbar mein Array of Bytes, den ich verschicke nicht so viel fassen kann.
ausblenden Delphi-Quelltext
1:
var Buffer : Array [0..4096of Byte; // ab 10000 oder so gibts nen Fehler					


D.h. ich muss die Datei scheinbar Stückchenweise vom client aus schicken und am server wieder zusammensetzen.

Und das ist es was mir die Probleme macht.

Ich habs auf verschiedene Arten probiert, nur entweder kam nur Müll an oder gar nix: z.B. so:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
Stream := TMemorystream.Create;   
Stream.LoadFromFile('D:\bild.jpg');         //
Stream.ReadBuffer(Buffer, sizeof(Buffer));      //  Sendet den Stream
Client.SendBuffer(Buffer,sizeof(Buffer));       //
Stream.position := stream.position + 4096// spult vor damit beim nächsten Buttonklick der nächste Teil //der Datei geschickt wird


Wie kann ich also die Datei in Teile verschicken, hab leider keinen Plan wie ich das anstellen soll.

mfg

Global Impact
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 28.07.06 18:12 
Moin!

user profile iconGlobalImpact hat folgendes geschrieben:
Ich schaffs ja mit Sendbuffer Daten zu senden, ich kann halt nur nicht 5 MB oder sowas in einen Puffer schicken, weil scheinbar mein Array of Bytes, den ich verschicke nicht so viel fassen kann.

Du weißt nicht wirklich, was du da so tust, oder... :? Das hat nix mit dem Buffer zu tun, du kannst abgesehen davon eh nicht mehr als 512 Bytes am Stück in ein UDP-Paket tun.

Mach das doch mal so:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
  var
    Buffer: String;
    Stream: TFileStream;
    Len: Int64;
begin
  SetLength(Buffer,512); // Buffer anlegen
  // Datei öffnen
  Stream := TFileStream.Create('datei.txt',fmOpenRead or fmShareDenyWrite);
  Len := Stream.Size; // Größe lesen
  while (Len > 0do begin // bis alles gesendet ist
    if (Len >= 512then begin // mehr als 512 Bytes übrig?
      Stream.Read(PChar(Buffer)^,512); // lesen
      Client.SendBuf(PChar(Buffer)^,512); // senden
      Dec(Len,512); // zählen
    end
    else begin // dito, aber nur den Rest bis 512 Bytes
      Stream.Read(PChar(Buffer)^,Len);
      Client.SendBuf(PChar(Buffer)^,Len);
      Len := 0;
    end;
  end;
  Stream.Free; // fertig, Datei zumachen

Damit kannst du die Datei in 512-Bytes-Blöcken senden. Es sollte sich übrigens nicht um eine strukturierte Datei handeln (wie z.B. JPG), da du die Integrität des Datenstromes (wie oben realisiert) nicht sicherstellen kannst. Dazu bräuchtest du ein Protokoll. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
GlobalImpact Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Sa 29.07.06 19:14 
Danke für die Antwort.

Hab den Quelltext an mein Programm angepasst und es geht!!

Danke nochmal

mfg

Global Impact
GlobalImpact Threadstarter
Hält's aus hier
Beiträge: 9



BeitragVerfasst: Sa 29.07.06 22:31 
Hallo nochmal, scheinbar gibts doch noch ein Problem.
Ich probier jetz seit 1 Tag und einer Nacht rum und kriegs net hin.

Ich kann zwar jetz Dateien versenden, aber wenn diese 8,5 KB (genauer 8704 Bytes) übersteigen, dann werden eben nur die genannten 8,5 KB gesendet und der Rest weggelassen.

Ich hab bereits den Buffer der Indysockets vergrößert, hat auch nix geholfen, hab ewig mit den Streams rumprobiert ...

Also versenden tut er mirs scheinbar noch, ich hab mir mit showmessage immer die Position des Strings anzeigen lassen, der versendet wird, und in dem Stream geht die Position in 512er Schritten bis zum Ende.

Beim empfangen is aber nach 8704 Bytes schluss.

Das is der Code mit dem ich empfang:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
procedure TForm1.ServerUDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);



begin

Adata.readbuffer(PChar(Puffer)^, 512) ;
fs.Writebuffer(PChar(Puffer)^, 512) ;


showmessage(inttostr(fs.size));


//fs.Position := fs.Position + 512;

//Puffer := '';
//setlength(Puffer, 512);

//showmessage(Puffer);
//Mstream.Position := MStream.Position + 512 ;


end;



FS ist ein TMemorystream.
Adata, der Stream aus dem UDPServer.

Ich blick nicht warum immer nur diese 8704 Bytes angenommen werden.

Weiss jemand Rat?

Danke für die Hilfe

mfg

Global Impact
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: So 30.07.06 23:48 
Moin!

Schau doch mal hier, vielleicht kommst du damit ja besser zurecht, als mit den Indies. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.