Dateien verschicken
-
Ich versuch derzeit in ein Programm von mir eine Funktion zu implementieren, die eine Datei über das Netzwerk verschickt.
Mir geht es dabei überhaupt nicht um den Quelltext sondern vielmehr um die Probleme die bei Platformunterschieden auftreten.Die Dateien sollen binär übertragen werden, das heißt, Executables sollen auf der Empfänger und der Absender Platform ausführbar sein, unabhängig von dem Betriebssystem.
Die Probleme, die sich stellen, sind:
- Haben beide Systeme die gleiche Byte-Order: Little-Endian oder Big-Endian, alle anderen Systeme ignorier ich, da sie eigentlich nur zu Entwicklungszwecken zum Einsatz kommen oder Uralt sind (middle-endian oder andere Quark).
- Sollen die Daten per UDP oder TCP übertragen werden? Oder gar eine Mischung wie sie in vielen Kommunikationsprogrammen eingesetzt wird?
- Wie wird die Länge der Datei übermittelt? Ein einfacher Int wäre eine Beschränkung auf eine Dateigröße von maximal 2milliarden Bytes (auf normalen x86 Systemen).
- Ist eine MD5 Überprüfung sinnvoll? Vorallem bei UDP denke ich, wäre sowas sinnvoll.
- Wie groß sollte ein Puffer zwischen Datei und Socket sein? Bzw. sollte bei kleinen Dateien versucht werden, es an einem Stück zu übertragen?
- Gib es sonst noch Probleme die auftreten können?Systeme die ich auf jedenfall unterstützen will sind x86, amd64, ia64, PowerPC und die Motorola CPUs. Mir geht es dabei überhaupt nicht um die Betriebssysteme. Executables sind auf jedem OS ausführbar, solange sie nach ELF formatiert sind und nicht auf Bibliotheken zugreifen.
Ich bräuchte jetzt Anregungen, diese Probleme zu lösen (dabei darf auch gerne Code gepastet werden, wobei mich dabei nur der Weg, nicht der Code slebst interessiert. Der Code stellt für mich später kein Problem dar) und vielleicht auch Hinweise auf andere Probleme.
Bei Little und Big Endian Unterscheidung müsste man ja mit einem 2 Byte Datentyp nur eine Bitverschiebung vornehmen und könnte das untere Bit überprüfen?
Gruß Avanox
PS:. Ich begrenze mich auf Systeme die 1 Byte mit 8 Bits darstellen

-
Avanox schrieb:
Die Probleme, die sich stellen, sind:
- Haben beide Systeme die gleiche Byte-Order: Little-Endian oder Big-Endian, alle anderen Systeme ignorier ich, da sie eigentlich nur zu Entwicklungszwecken zum Einsatz kommen oder Uralt sind (middle-endian oder andere Quark).Byte-order ist nur interessant für Dinge wie die Längenangabe der Datei. Die Datei wird sowieso byte-weise übertragen. Bei der byte-order würd ich mich auf ein System festlegen und dann eine Funktion "int to_network_byte_order(int)" o.ä. schreiben, die je nach Architektur leer ist oder eben die Bytes vertauscht.
Avanox schrieb:
- Sollen die Daten per UDP oder TCP übertragen werden? Oder gar eine Mischung wie sie in vielen Kommunikationsprogrammen eingesetzt wird?
Ich würde sagen: ganz klar TCP.
Bei UDP musst dir die Frage stellen ob du verlorene Pakete tolerieren kannst. Die Antwort ist hier nein, demnach kommt UDP nicht in Frage. Andernfalls würdest du nur TCP nachbauen.Avanox schrieb:
- Wie wird die Länge der Datei übermittelt? Ein einfacher Int wäre eine Beschränkung auf eine Dateigröße von maximal 2milliarden Bytes (auf normalen x86 Systemen).
Um für alles gewappnet zu sein könntest du z.B. ein Klartext-Protokoll definieren, das die Länge als newline-terminierte Dezimal-Zahl überträgt. Alternativ könntest du einfach einen 64-Bit-unsigned nehmen, das sollte noch für einige Jahre genügen.

Avanox schrieb:
- Ist eine MD5 Überprüfung sinnvoll? Vorallem bei UDP denke ich, wäre sowas sinnvoll.
TCP garantiert dir im Prinzip die fehlerfreie Übertragung, mit einer Prüfsumme über die gesamte Datei kannst du aber Fehler minimieren (und wenn es andere Fehler wie Festplatten- oder Implementierungs-Fehler sind).
Avanox schrieb:
- Wie groß sollte ein Puffer zwischen Datei und Socket sein? Bzw. sollte bei kleinen Dateien versucht werden, es an einem Stück zu übertragen?
Der sollte nicht zu klein sein. Die Netzwerk-Treiber sorgen selbst für eine Aufteilung in kleine Pakete. Am besten funktioniert das, wenn du dem Socket große Blöcke zum Versenden oder Empfangen übergibst.
-
Christoph schrieb:
Avanox schrieb:
- Wie wird die Länge der Datei übermittelt? Ein einfacher Int wäre eine Beschränkung auf eine Dateigröße von maximal 2milliarden Bytes (auf normalen x86 Systemen).
Um für alles gewappnet zu sein könntest du z.B. ein Klartext-Protokoll definieren, das die Länge als newline-terminierte Dezimal-Zahl überträgt. Alternativ könntest du einfach einen 64-Bit-unsigned nehmen, das sollte noch für einige Jahre genügen.

Oder du benutzt ein Prinzip für Werte variabler Länge wie es zum Beispiel in SMF(=.mid)-Dateien gehandhabt wird (1xxxxxxx-1yyyyyyy-0zzzzzzz wird zu xxxxxxxxyyyyyyyzzzzzzz). Oder du packst an den Anfang jedes Puffers ein Statusbyte, das nur sagt, ob nun der letzte Block kommt. Mit beidem sparst du dir Big/Little-Endian-Gehopse und kannst völlig beliebig große Dateien versenden.
Christoph schrieb:
Avanox schrieb:
- Ist eine MD5 Überprüfung sinnvoll? Vorallem bei UDP denke ich, wäre sowas sinnvoll.
TCP garantiert dir im Prinzip die fehlerfreie Übertragung, mit einer Prüfsumme über die gesamte Datei kannst du aber Fehler minimieren (und wenn es andere Fehler wie Festplatten- oder Implementierungs-Fehler sind).
Dann aber schon CRC, oder?
-
Du erwähnst jetzt die Network-Byte-Order. Was aber, wenn beide Systeme die gleiche, aber nicht die Network-Byte-Order verwenden. Dann wäre es sinnlos, alles erst zu konvertieren, desshalb will ich ja die Byte Order herausfinden.
Und mit der Byte Order hast du natürlich Recht, binäre Formate interessieren sich ja nicht für die Byte Order.
Zu der FTP/UDP Frage. Ich hab leider noch nie mit UDP gearbeitet, wesshalb ich auch nicht weiß, wieviel dort wirklich verloren geht. Klar, leisten kann ich es mir nicht, wenn es aber nur selten vorkommt, wäre es ein ziemlicher Performance Gewinn und mit MD5 Prüfsummen doch gut überprüfbar?
Vorallem im LAN sollte es da doch nicht so große Störungen geben?Puffer Größe: "groß" ist ziemlich relativ

4096 Byte? Ist das groß, klein, winzig, rießig bei dir?Zur Dateilänge: Ich hab mir auch schon überlegt, sie als string zu übertragen. Dürfte ja bei den paar Bits keine Performance Probleme machen

Wobei ein 64Bit Wert einfacher zu handhaben wäre und ich dabei Dateien mit bis zu 18.446.744.073.709.551.616 Byte (18PB?) schicken könnte => Ich glaube, da würde das schicken der Datei mit heutigen Methoden länger dauernd, als mein Programm jemals überleben wird
-
Avanox schrieb:
Du erwähnst jetzt die Network-Byte-Order. Was aber, wenn beide Systeme die gleiche, aber nicht die Network-Byte-Order verwenden. Dann wäre es sinnlos, alles erst zu konvertieren, desshalb will ich ja die Byte Order herausfinden.
Glaubst du wirklich, dass sich das lohnt? Ich glaube kaum.
Avanox schrieb:
wesshalb ich auch nicht weiß, wieviel dort wirklich verloren geht.
Das weiß dein Programm leider auch nicht, das ist ja das Problem.
Avanox schrieb:
Klar, leisten kann ich es mir nicht, wenn es aber nur selten vorkommt, wäre es ein ziemlicher Performance Gewinn und mit MD5 Prüfsummen doch gut überprüfbar?
Toll, und wenn dann was schief läuft, dann musst du nochmal schicken.
Und genau das macht TCP ja auch, nur viel besser als du es wahrscheinlich hinbekommst
-
Avanox schrieb:
Du erwähnst jetzt die Network-Byte-Order. Was aber, wenn beide Systeme die gleiche, aber nicht die Network-Byte-Order verwenden. Dann wäre es sinnlos, alles erst zu konvertieren, desshalb will ich ja die Byte Order herausfinden.
Und mit der Byte Order hast du natürlich Recht, binäre Formate interessieren sich ja nicht für die Byte Order.
Du hast deine Frage praktisch schon selbst beantwortet. Die Byte-order ist nur für den Header, in dem Dateilänge u.ä. steht, relevant. Und das auch nur, falls du kein text-basiertes Protokoll entwirfst wie z.B. HTTP. Für die paar Bytes lohnt es sich nicht vorher die byte-order auszuhandeln um Geschwindigkeit herauszuholen. Du musst außerdem bedenken, dass aus Sicht der CPU das Netzwerk in der Regel im Zeitlupentempo läuft. Die Übertragung eines einzelnen Bytes dauert aus Sicht der CPU seehr lange (Gigabit-Anbindungen außen vor gelassen). Eine byte-order-Konvertierung einsparen bringt also von der Geschwindigkeit her überhaupt nichts.
Avanox schrieb:
Zu der FTP/UDP Frage. Ich hab leider noch nie mit UDP gearbeitet, wesshalb ich auch nicht weiß, wieviel dort wirklich verloren geht. Klar, leisten kann ich es mir nicht, wenn es aber nur selten vorkommt, wäre es ein ziemlicher Performance Gewinn und mit MD5 Prüfsummen doch gut überprüfbar?
Der Performance-Gewinn wird völlig zunichte gemacht, wenn du keine verlorenen oder falsch sortierten Pakete tolerieren kannst. Dann musst du nämlich selber dafür sorgen, dass
a) die ankommenden Pakete richtig sortiert werden
b) verlorengegangene Pakete neu angefordert werden.Eine Prüfsumme brauchst du bei UDP aber genausowenig wie bei TCP. Denn UDP garantiert dir zwar nicht, dass ein Paket ankommt, aber wenn es ankommt, dann vollständig.
UDP bringt dir nur dann Geschwindigkeit, wenn du ein paar verlorene Pakete tatsächlich tolerieren kannst, diese also nicht erneut anfordern musst. Voice over IP ist zum Beispiel so ein Fall, ein kurzer Knackser im Gespräch kann besser sein als eine Latenzzeit von 1 Sekunde.
Avanox schrieb:
Puffer Größe: "groß" ist ziemlich relativ

4096 Byte? Ist das groß, klein, winzig, rießig bei dir?Ich hab länger nichts mehr mit Sockets gemacht, aber ich dachte eher an Megabyte als an Kilobyte. Von der Größenordnung vielleicht 1-4 MB.
Avanox schrieb:
Zur Dateilänge: Ich hab mir auch schon überlegt, sie als string zu übertragen. Dürfte ja bei den paar Bits keine Performance Probleme machen

Zum Beispiel bei HTTP wird die Länge auch als Text übertragen.
-
Wie groß sollte ein Puffer zwischen Datei und Socket sein?
4 - 64 kb