Forum: PC-Programmierung TCP/IP Grundlagen Frameanfang erkennen


von Jens S. (jenss)


Lesenswert?

Hallo zusammen,

ich habe eine Frage bezüglich einer TCP/IP Kommunikation.
Dies ist ja einfach ein Datenstream und wenn ich mir nun ein Protokoll, 
wie die Daten da übertragen werden, ausdenke, dann muss ich auch selber 
erkennen wo mein Frame anfängt und wo er aufhört, oder?

Wie geht das denn bei anderen Protokollen wie z.B. Modbus TCP/IP?

Wenn ich die recv. Funktion eines Sockets aufrufe und dort kein gültiger 
Frame anfang liegt habe ich doch ein Problem, korrekt?
Gibt es eine Sinnvolle Lösung für dieses Problem?

Besten Gruß
Jens


Edit: Bei mir geht es eben auch dadrum, dass ich in meinem eigenem 
"Frame" mehr Daten als die 1500 Bytes übertragen möchte und ggf. mehrere 
TCP/IP Frames dafür benötigt werden.

von Peter II (Gast)


Lesenswert?

Jens S. schrieb:

das Wird auf der untersten ebende gemacht, also nicht im IP sondern auf 
der MAC ebende.

Ich konnte jetzt auf die schnell nicht finden wie dort ein anfang 
definierst ist, als beispiel kannst du dir aber HDLC anschauen dort gibt 
es eine feste Bitfolge.

http://de.wikipedia.org/wiki/High-Level_Data_Link_Control

von micha54 (Gast)


Lesenswert?

Hallo,

da ich mich gerade vor 2 Monaten mit dem gleichen Thema beschäftigt 
hatte wage ich hier mal zu widersprechen.

TCP liefert eigentlich nur einen Stream, d.h. es gibt keine Erkennung 
logischer Frames auf der Applikationsebene. Was man erkennt ist 
allerdings das allererste Byte, und die Übertragung ist gesichert, d.h. 
es kann keines unerkannt verloren gehen.

Viele einfache Protokolle sind textorientiert (HTTP, FTP, SMTP, usw.), 
so daß man über das Zeilenende einen Parser steuern kann.

Wir haben für unser binäres Protokoll Frames definiert, die z.B. mit der 
Längeninformation beginnen, d.h.
- 2 Bytes lesen, Länge n auswerten
- weitere n bytes lesen, das sind die Daten
- nochmal 4 bytes Prüfsumme lesen
Was tun, wenn die Prüfsumme nicht stimmt ?
Bei uns kommt dann irgendwann ein Read-Timeout, nach dem wir von vorn 
beginnen.

Es geht sicher auch einfacher, aber wie ?

Gruß,
Michael

von Jens S. (jenss)


Lesenswert?

Hallo Michael,

genau das Vorgehen hatte ich mir nun auch überlegt. Die Frage bleibt 
dann einfach ob es noch eine bessere Methode gibt.

Grundsätzlich dürften ja im RecvBuffer des TCP/IP Stacks keine 
verwahrlosten Daten sein wie z.b. Störbytes bei einer 
Seriellenkommunikation.

von micha54 (Gast)


Lesenswert?

Hallo Jens,

genau das war so, mit TCP/IP war die Kommunikation absolut sauber.

In unserem Fall lag optional ein UMTS-Modem per serieller Schnittstelle 
in der Übertragung (kein TCP/IP), und das hat gelegentlich Bytes 
verloren. Das hat dann unserr Lesen mit Timeout abgefangen.
Störbytes gab es aber keine.

Gruß,

Michael

von Clemens S. (zoggl)


Lesenswert?

wenn es nicht schnell sein muss kannst du den socket auch öffnen 
schließen.
socket auf, daten rein, socket zu. ist langsam, verhindert aber dass 
sockets offen bleiben, du musst dich nicht um start oder end oder 
prüfsumme kümmern.


ein anderes Problem beim lesen aus einem offenen socket ist dass zwar 
alle pakete übertragen werden, diese aber in unterschiedlicher 
reihenfolge bei dir auschlagen dürfen. es gibt also die möglichkeit dass 
dir im stream ein stück fehlt, das zwar danach gelifert ( oder noch 
einmal vom socket angefordert wird), du aber bereits ein streamstück mit 
"Loch" gelesen hast.

siehe http://commons.wikimedia.org/wiki/File:Tcp_transfer.png

wenn es dir aslo nicht auf das letzte ms ankommt dann mach das ding auf 
und wieder zu nach jeder übertragung.

von Peter II (Gast)


Lesenswert?

Clemens S. schrieb:
> ein anderes Problem beim lesen aus einem offenen socket ist dass zwar
> alle pakete übertragen werden, diese aber in unterschiedlicher
> reihenfolge bei dir auschlagen dürfen. es gibt also die möglichkeit dass
> dir im stream ein stück fehlt, das zwar danach gelifert ( oder noch
> einmal vom socket angefordert wird), du aber bereits ein streamstück mit
> "Loch" gelesen hast.

nein das kann nicht passieren, sonst könnte man mit TCP gar nicht 
arbeiten. Das kann nur bei UDP passieren. Der Stack gibt dir die packete 
immer in der richtige Reihenfolge egal wie sie am PC eintreffen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Clemens S. schrieb:
> ein anderes Problem beim lesen aus einem offenen socket ist dass zwar
> alle pakete übertragen werden, diese aber in unterschiedlicher
> reihenfolge bei dir auschlagen dürfen. es gibt also die möglichkeit dass
> dir im stream ein stück fehlt, das zwar danach gelifert ( oder noch
> einmal vom socket angefordert wird), du aber bereits ein streamstück mit
> "Loch" gelesen hast.

Das sind ja ganz neue Erkenntnisse! Ich glaube alle außer dir benutzen 
ein anderes TCP/IP Protokoll...

Clemens S. schrieb:
> wenn es nicht schnell sein muss kannst du den socket auch öffnen
> schließen. socket auf, daten rein, socket zu

Dann kann er auch gleich UDP mit einem ACK Verfahren nutzen...

von Clemens S. (zoggl)


Lesenswert?

ja, die reihenfolge stimmt und es werden auch alle daten übertragen. bis 
zum ack der verbindung ist es aber nicht sicher dass du das paket auch 
bereits zum abruf hast

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Clemens S. schrieb:
> ja, die reihenfolge stimmt und es werden auch alle daten
> übertragen. bis zum ack der verbindung ist es aber nicht sicher dass du
> das paket auch bereits zum abruf hast

Dunkel ist der Sinn deiner Worte...

von Jens S. (jenss)


Lesenswert?

Also wenn ich meine recv bsd socket Funktion aufrufe, dann sind die 
Daten dort gültig. Die verlorenen bzw. falsche Telegramreihenfolge ist 
ja alles ein paar Ebenen tiefer. Darum möchte ich mich garnicht kümmern 
und macht ja auch der TCP/IP Stack von Windows CE.

Somit werde ich zur Sicherheit noch einen Timeout einbauen und eine CRC 
Checksumme.

Immer den Socket neu aufmachen bedeutet ja auch eine neue Task zu öffnen 
und, bei meiner aktuellen Konsturktion, auch etwas mehr aufwand weil 
beim Anlegen des Clients ein paar Sachen passieren. Alternativ müsste 
man drüber nachdenken 2 Socket Verbindungen aufzubauen. Eine mit der 
Configuration/Alive und eine für den Datenaustausch der immer geöffnet, 
geschlossen wird.

von (prx) A. K. (prx)


Lesenswert?


von JojoS (Gast)


Lesenswert?

Timeout ist wichtig, auf CRC kannst du verzichten.
Die Kommunikation fängt ja so an das der Client einen Verbindungsversuch 
zum Server macht. Wenn der aktzeptiert sind die Buffer leer und die 
Verbindung ist synchron. Jetzt sollte dein Protokoll so aussehen das du 
z.B. zuerst eine Messagelänge und dann eine ID sendest. Der Empfänger 
kann dann den Rest der Message lesen und die nächste muss halt wieder 
genauso anfangen. Solange Bytes beim Empfänger ankommen sind bei TCP 
auch in der richtigen Reihenfolge. Durch die Angabe der Länge kann der 
Empfänger auch unbekannte Nachrichten empfangen ohne ausser Tritt zu 
kommen.
Was aber passieren kann ist ein Verbindungsabbruch, z.B. durch Stecker 
ziehen. Das kriegt der Empfänger evtl nicht mit und deshalb ist ein 
Watchdog + Timeout nötig. Wenn der Gegner das Timeout erkennt muss die 
Verbindung geschlossen und wieder neu aufgebaut werden damit es wieder 
synchron losgehen kann.

von Jenss (Gast)


Lesenswert?

Die recv bzw. send Funktion geht doch mit einem Wert <0 raus und erkennt 
den Connection_Lost und ich weiß, dass die Verbindung weg ist. Dann wird 
der Socket mit dem Client geschlossen und auf eine neue Verbindung 
gewartet und alles fängt von vorne an :)
Also ich hatte bei mir nicht geplant auch Frames, die mit eineem 
Verbindungsproblem zerstückelt wurden, wieder weiter zu verarbeiten.

von JojoS (Gast)


Lesenswert?

Jenss schrieb:
> ie recv bzw. send Funktion geht doch mit einem Wert <0 raus

Das kommt auf die Verbindungsstrecke an, es ist nicht gut sich darauf zu 
verlassen. Wenn man das Netzwerkabel direkt vom Rechner abzieht wird das 
mittlerweile durch den IP Stack geleitet und der Applikation gemeldet. 
Sind aber Router, Switches, Glasfaser oder Funk dazwischen bekommt man 
das nicht sicher mit wenn man in einer recv() Schleife hängt. Deshalb 
ist die Timeout Erkennung auf Applikationsebene wichtig, das macht den 
Unterschied zwischen einem funktionierenden und einem robusten Programm 
aus.

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.