Forum: PC-Programmierung Fragen: TCP/IP socket + Paketübertragung


von 900ss (900ss)


Lesenswert?

Hallo,

ich habe NULL Erfahrungen mit übertragungen über Netzwerk-Sockets per 
TCP/IP. Deshalb hab ich ein paar Fragen.

Ich möchte Kommandos + Parameter übertragen. Das ganze soll unter Linux 
passieren. Es funktioniert im Prinzip schon. Also ich kann Sockets auf 
Sender und Empfängerseite öffnen, die Verbindung kommt zustande 
(connect) und ich kann Daten übertragen.

Meine Frage ist nun, angenommen die Paketlänge ist konstant. Kann ich 
auf der Empfängerseite solange fread(...) aufrufen, bis die erwartete 
Byteanzahl empfangen wurde? So mache ich es im Moment und es 
funktioniert auch auf meinem Tisch. Kann der Emfänger nicht asynchron 
werden? Also mittem im Paket aufsetzen (wodurch auch immer) und dann 
synchronisiert sich der Empfänger nie wieder. Oder passiert das nicht? 
Also das Paket, was mit einer Länge sagen wir 4kB abgeschickt wurde, 
kommt auch so an?

Ich denke ich muß da auch Timeouts über select() implementieren in der 
Schleife, die per fread() die Daten einsammelt. Und dann neu aufsetzen, 
falls was schief geht. Und dann kommt das nächste Problem. Nach einem 
Timeout muß ich ja an der richtigen Stelle aufsynchronisieren, also am 
Paketanfang. Also erstmal eine eindeutige Kennung empfangen und dann 
weiter?

Durch die Defragmentierung kommen die Daten ja auch nicht in einem 
Rutsch an sondern sie kommen evtl. in kleinen Häppchen.

Vielleicht denke ich auch viel zu kompliziert und es ist alles ganz 
einfach. Hab noch nie damit gearbeitet und deshalb diese Fragen.

Über Antworten freue ich mich, danke.

900ss

von diereinegier (Gast)


Lesenswert?

TCP stellt Dir einen verläßlichen Byte-Stream zur Verfügung. Hab' 
Vertrauen, die meisten TCP/IP-Software-Stacks sind bereits gut gereift.

Die Aufteilung in Pakete mußt Du selbst machen, z.B. durch eine 
Längenangabe am Anfang eines jeden Pakets.

Wenn irgendetwas außer Tritt gerät, dann ist das mit 99,999%iger 
Wahrscheinlichkeit ein Programmierfehler bei Dir. Den reparierst Du akut 
durch Abbrechen und Neuverbinden und mittelfristig durch Korrektur 
Deines Programms.

Wenn es TCP tatsächlich nicht gelingt, zu tun, wofür es da ist, dann 
wird read/write was auch immer mit einem 0 gelesenen/geschriebenen Bytes 
zurückkommen und in errno oder sonstwo wird ein Fehlerkode stehen, das 
hängt an der verwendeten Bibliothek. Und dann hilft natürlich auch ein 
Neuaufbau der Verbindung.

von Rolf M. (rmagnus)


Lesenswert?

TCP kümmert sich automatisch um Retransmits von verlorengegangen oder 
bei der Übertragung verfälschten und die Beseitigung von ggf. doppelt 
angekommenen Paketen. Weiterhin sorgt es auch dafür, dass alle Daten 
genau in der Reihenfolge ankommen, in der sie auch gesendet wurden.
Es garantiert dagegen nicht, dass die Blöcke, in denen die Daten 
empfangen werden, genau so aufgeteilt sind, wie sie gesendet wurden.
Anders gesagt: TCP ist Stream-orientiert. Alle Bytes, die gesendet 
wurden, kommen genau in der Reihenfolge und Anzahl auch wieder an, so 
lange die Verbindung nicht abgebaut wird oder abreißt.

900ss D. schrieb:
> Meine Frage ist nun, angenommen die Paketlänge ist konstant. Kann ich
> auf der Empfängerseite solange fread(...) aufrufen, bis die erwartete
> Byteanzahl empfangen wurde?

So macht man das normalerweise. Allerdings eher mit read() oder recv(). 
fread gehört eigentlich eher zur Standard-C-Schnittstelle für 
Dateioperationen über FILE*.

> Kann der Emfänger nicht asynchron werden? Also mittem im Paket aufsetzen
> (wodurch auch immer) und dann synchronisiert sich der Empfänger nie
> wieder. Oder passiert das nicht?

Nein.

> Also das Paket, was mit einer Länge sagen wir 4kB abgeschickt wurde,
> kommt auch so an?

Es kommt nicht unbedingt als genau ein 4kB-Paket wieder an, aber alle 
Bytes kommen wieder genau so an, und es kommt genau auf die vorher 
gesendeten Bytes folgend an. Daß zwischendrin mal was fehlt, kommt nicht 
vor.

> Ich denke ich muß da auch Timeouts über select() implementieren in der
> Schleife, die per fread() die Daten einsammelt. Und dann neu aufsetzen,
> falls was schief geht. Und dann kommt das nächste Problem. Nach einem
> Timeout muß ich ja an der richtigen Stelle aufsynchronisieren, also am
> Paketanfang.

Was willst du denn nach dem Timeout machen? Einfach nochmal lesen? Dann 
hättest du deinen Timeout ja einfach umgangen. Du musst schon die 
Verbindung komplett ab- und wieder neu aufbauen. Und damit bist du ja 
wieder am Anfang einer neuen Verbindung und alles ist ganz von selbst 
wieder aufsynchronisiert.

> Durch die Defragmentierung kommen die Daten ja auch nicht in einem
> Rutsch an sondern sie kommen evtl. in kleinen Häppchen.

Richtig. Das wird durch dein wiederholtes Lesen abgedeckt.

: Bearbeitet durch User
von 900ss (900ss)


Lesenswert?

Oh danke euch beiden, das ging ja schnell :)

diereinegier schrieb:
> TCP stellt Dir einen verläßlichen Byte-Stream zur Verfügung. Hab'
> Vertrauen, die meisten TCP/IP-Software-Stacks sind bereits gut gereift.

Hehe, ohne Erfahrung Vertrauen zu haben ist für mich zumindest schwer :) 
Aber wirklich Zweifel hatte ich nicht. Hab nur lieber nochmal fragen 
wollen. Das ganze wird unter Linux laufen, soviel zum TCP/IP Stack.

Rolf Magnus schrieb:
> Allerdings eher mit read() oder recv().
> fread gehört eigentlich eher zur Standard-C-Schnittstelle für
> Dateioperationen über FILE*.

Ich nutze auch read(). Hatte mich vertan.

Also dann mache ich im Prinzip schon alles richtig so wie ich es 
implementiert habe.

was mir noch durch den Kopf geht, wenn man verschieden lange Pakete hat, 
dann wird man wohl erst ein Längenfeld senden und dann die Anzahl Bytes, 
die im Längenfeld stand. Oder gibt es bessere Lösungen?

Und wie behandelt man eigentlich "schlechte" Verbindungen? Ich denke 
kann ja schonmal sein, dass die Verbindung sehr "stottert". Wenn das zu 
schlimm wird und abrechen will, dann muß man ja schon mit Timeout 
arbeiten. Wie lang macht man diese Zeiten sinnvollerweise? Ok, hängt 
sicher auch von der Anwendung ab.

: Bearbeitet durch User
von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Wenn du im lokalen Netz agieren willst wäre UDP auch eine Option wenn du 
Paketorientiert arbeiten willst.

Ansonsten gibt es ja schon soooo viel Fertige Protokolle warum also 
nicht mal schauen ob was für dich dabei ist? Wenn ich Linux lese würde 
sich doch ggf. sogar was High-Level anbieten wie HTTP...

von 900ss (900ss)


Lesenswert?

Läubi .. schrieb:
> Wenn du im lokalen Netz agieren willst wäre UDP auch eine Option wenn du
> Paketorientiert arbeiten willst.

Ist nicht lokales Netz, nur wenn es bei mir auf dem Tisch steht :)

>
> Ansonsten gibt es ja schon soooo viel Fertige Protokolle warum also
> nicht mal schauen ob was für dich dabei ist? Wenn ich Linux lese würde
> sich doch ggf. sogar was High-Level anbieten wie HTTP...

Es war tatsächlich eine Überlegung, auf der einen Seite einfach einen 
Webserver laufen zulassen. Ich habe aber auch keine Ahnung, wie 
resourcenaufwendig bezüglich Übertragunsdatenmenge das Ganze bei einem 
Webserver ist.

Dazu habe ich mir auch Node-Red von IBM angesehen. Das läuft ja sogar 
auf einem Rasp-PI. Aber das kommt jetzt vom Thema ab. Mich interessieren 
eher die Antworten auf meine Fragen oben.

von greg (Gast)


Lesenswert?

Ja, header mit Länge ist die "Standardlösung" in dem Fall. Oder wenn die 
Daten es hergeben ein eindeutiges Trennzeichen (bei textbasierten 
Protokollen halt z.b. '\n')

Oder halt fertige Lösungen, ich möchte da noch auf google Protocol 
Buffers oder deren "Nachfolger" Captn Proto verweisen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

900ss D. schrieb:
> Es war tatsächlich eine Überlegung, auf der einen Seite einfach einen
> Webserver laufen zulassen. Ich habe aber auch keine Ahnung, wie
> resourcenaufwendig bezüglich Übertragunsdatenmenge das Ganze bei einem
> Webserver ist.

HTTP an sich ist sehr sparsam und auch sehr felxibel, du kannst im 
Notfall sogar die Daten zwischen Server/Client komprimieren. 
http://www.lighttpd.net/ wäre z.B. eine sehr leichtgewichtige 
Implementierung, wenn das Ziel ein "normales" Linux ist wäre Apache 
sicher auch möglich.

Vorteil ist auch einfach: Du findest sehr viel Client-Libs die du nutzen 
kannst, und selbst ohne ist der Client-Part sehr einfach zu stricken im 
Notfall kannst du auf HTTP1.0 downgraden.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.