Hallo Leute, ich bin auf der Suche nach einem "guten" Algorithmus für die Datenkapselung bei verschiedenen Protokolle. Also das weiterleiten und ein betten der Nutzdaten in den Protokollen. Ich möchte mein Problem anhand des SNMP-Protokoll erklären. Wenn ich Daten von Ethernet (bzw SLIP) bekomme, kann ich den Stream, anhand der Heads dekodieren und bearbeiten. Die Telegramme werden in Richtung SNMP immer kleiner und ich kann den "Start"-Pointer und die Länge an die anderen Protokolle weiterleiten. (relative einfach) Wie sieht es jetzt in die andere Richtung aus: Das Telegramm vom SNMP muss nun von den unteren Schichten mit ihren Headern erweitert werden! (Das Telegramm wird größer) Ich hab mich etwas umgesehen, aber eine gute Lösung konnte ich für eine MC-Implementierung nicht finden. 1) Lösung Wenn ich nun den SNMP Datensatz an den Anfang des Buffers schreiben würde, könnte ich keine weiteren Header schreiben, ohne das ich den SNMP-Datensatz nach hinten verschieben muss.(nicht gut, kostet "viel Zeit" pro Schicht!) 2) Lösung Diese hab ich sehr häufig gefunden, aber ist mir zu direkt. Der SNMP-Handler schreibt ALLE Schichten in einem Rutsch, d.h. er macht Ethernet, IP, udp. Das möchte ich nicht, jede Schicht sollte für sich autark sein! 3) Lösung Eine doppelt oder einfach verkettete Liste! Fand ich sehr gut, denn das Telegramm kann somit in beide Richtungen wachsen und ist somit sehr autark. (aber nicht für MC geeignet, selbst mit einer statischen Liste ohne malloc kann ich mir es nicht wirklich effektiv für einen MC vorstellen. (Speicher, Verwaltung usw.) 4) Lösung Die ist mir noch eingefallen, aber ein paar Bekannte meinten schon es wäre etwas zu sehr an den Haaren herbei gezogen. Ich schreibe die Nutzdaten vom SNMP Rückwerts in den Buffer, die Heads der anderen Protokollen auch, somit wächst das Telegramm immer am ende weiter. Bei der Ausgabe muss ich das Telegramm dann auch Rückwerts ausgeben. (naja) 5) Lösung Was auch noch sehr verbreitet war, war das alle schichten sich einen Buffer dynamisch anfordern und den alten Inhalt jeweil koperen. (wie 1, viel Zeit, hab kein malloc!) Was gibs denn noch so auf dem Markt? Was hab ich übersehen? Warum werden hier bei den Projekten mit AVR und INET immer die direkte Methode bevorzugt? (L.2) Das hat nämlich auch mein ehemaliger Kollege so gemacht, jetzt kann ich eine Menge Protokolle neu überarbeiten weil sich ein paar Schichten geändert haben. Ich hoffe Ihr habt noch was im Ärmel. Danke. mfg Stephan
:
Ich wäre (allerdings ohne selbst jemals einen Protokollstack geschrieben zu haben) für Lösung 3), also eine Art verkettete Liste. Wobei man sich noch überlegen könnte, ob wirklich alles dynamisch angelegt werden muss. Speziell für die Schichten mit festen Datenlängen würden ja statische Buffer ausreichen. Und für die Schichten mit variabler Länge dann eben dynamisch anlegen und aus den statischen Buffern per Pointer verweisen, oder (wenn sich die Länge grob eingrenzen lässt) sogar auch statisch mit worst-case-Länge.
Wenn du weißt, wie groß deine Header insgesamt höchstens werden, dann reservierst du halt diesen Platz für den schlimmsten Fall vor der Stelle, an der der SNMP-Handler seine Nutzdaten hinschreibt. Jede Schicht packt halt ihren Header vor die Nutzdaten der verkapselten Schicht und fertig ist die Kiste. Der Overhead hält sich in Grenzen und du sparst dir die Zeiger, die du dir bei verketteten Listen merken musst. Und zum Schluss liegt das Paket in einem Stück im Speicher. Macht uIP gewissermaßen so, da gibt es halt einen Zeiger für die Nutzdaten, und die Header liegen davor (was bei Ethernet+IP in deren Spezialfall einfach ist, weil sie eine feste Länge haben).
Mit einem microcontroller macht man gerne alle schichten auf's mal. Denn man moechte damit fertig werden, zwar schnell, und zuverlaessig. Gleichzeitig moechte man dynamische Datenstrukturen vermeiden. Also keine Malloc und dergleichen. Unter berucksichtigung dieser Randbedingungen ist man sofort bei der direkten implementation.
Nabend, danke für die Antworten. @Oktav Oschi Ja das sehe ich hier bei mir auch, aber nun muss ich jedes Protokoll neu bearbeiten, weil sich das NET-IF geändert hat und noch 2 neue Bridge(Brücken?)-Protokolle hinzukommen. Jetzt macht die direkte Methode einen ziemlichen Arbeitsaufwand. Da ich nicht der Entwickler war und der Kollege keine Doku gemacht hat, habe ich besonderen Spaß. @Dennis S. Das geht nur wenn man weiß was drunter an Schichten liegt. siehe Lösung 2. ob ich Platz mache oder es direkt mache, ist für mich das gleiche. @Uwe ... Ja, so gehts mir auch. Ich habe zwar schon einige Protokolle programmiert aber die hatten nur 1 oder 2 Schichten (und festes Interface), da war das nicht so wild. Das Problem ist auch das zu den bestehenden Protokollen noch einige hinzukommen sollen und diese dann wieder per Konfiguration aller #ifdef auch wieder ausgeschlossen werden sollen. Deshalb wäre mir eine Weiche-Kopplung der Protokolle untereinander lieber. mfg Stephan
Hi Leute, ab ich echt schon alle Möglichkeiten erkannt? Kennt keiner noch andere Methoden dafür? Wieso wird nun die "Direkte" Methode bevorzugt? Ich muss deshalb viele "ifdef's" einbauen, um die Anzahl der Protokolle und Interface konfigurierbar zu machen. (macht den Code nicht gerade leicht zu lesen) Wir haben hier bei uns, 6 Geräte-Familien die verschieden Stacks benötigen und es muss doch möglich sein dafür was passendes zu schreiben. Oder ich schreibe, 6 mal einen Neuen Stack, was aber keinen wirklich glücklich machen wird. Was mir wirklich sorgen macht sind nicht die Protokolle selber, sondern eher die Interface von denen ich sie bekomme: Funk, RS232, USB, Ethernet usw. mfg Stephan
Ich werfe jetzt einfach mal das Stichwort 'code generieren' in die Runde. Die einzelnen Stacks würden dann während dem Buildprozess generiert werden. Das würde die #ifdefs ersetzen. Wie das dann genau aussehen wird, weiß ich allerdings auch noch nicht.
Hallo, Ich weis nicht welchen µC du benutzt, aber wenns ein etwas besserer ist dann kannst du darüber nachdenken, die einzelnen Protokollschichten in getrennten Arrays zu "bauen", und diesen dann per DMA an die Hardware zu schicken. Der DMA-Controller kann dann die einzelnen Schichten in der richtigen Reihenfolge zusammenbasteln und rausschicken. Nur beim einlesen musst du dir was anderes überlegen, aber das sollte auch nicht das Problem sein, das sich die einzelnen Schichten die Daten die sie brauchen, aus dem Empfangspuffer raussuchen. Gruß, Stephan
Ich habe schon mal angefangen einen Stack zu schreiben. Am sinnvollsten ist es, wenn man annimmt, dass alle Header, die noch vor das (in diesem Falle SNMP) Paket geschrieben werden müssen, eine maximale oder konstante Größe haben! Wenn du nun das Antwortpaket schreibst (in einer oberen Schicht), holst du dir vom Stack die Adresse für den Schreibpuffer, wo die Antwort reinkommt. Der Stack berechnet diese Adresse mit Hilfe seines (statischen) Sende- und Empfangspuffers PLUS die Worst-Case Größe aller Header, die noch vor das Paket gesetzt werden müssen. z.B. Headergrößen Ethernet: 14 Bytes max. IP: 60 Bytes max. UDP: 8 Bytes max. Dann dürfte die SNMP Anwendung an der Adresse Puffer + (14 + 60 +8) anfangen das SNMP Datagramm zu schreiben. Dann muss man nur noch konkret in jedem Falle schauen wie groß IP, UDP und Ethernet Header sind und den tatsächlichen Startpunkt herausfinden, sodass der Header direkt an den zuvorgeschriebenen Header anliegt. Das sollte am einfachsten für kleine Mikrocontroller zu realisieren sein. Bedenke, dass die unterstützten Protokoll-Features für den Stack bei kleinen Mikrocontrollern sich nicht dauernd ändern. Sodass die tatsächlich genutzten (nicht die Worst-Case) Headergrößen zur Compile-Zeit komplett fix sind und sich nicht mehr ändern können (außer in Ausnahmefällen). Somit ist eigentlich diese Variante am effektivsten, wenn man mit defines arbeitet. Hat man den Stack einmal per defines konfiguriert, steht die nötige Größe des Gesamtpuffers, sowie die Startpunkte der einzelnen Protokolle fest und der Compiler optimiert. So Sachen wie Listen sind eigentlich Overkill. Die braucht man eher bei dynamisch sich ändernden Daten. Sie würden zwar das Programmieren vereinfachen, weil man dann nicht soo haargenau jeden Fall auf Buffer-Overflows durchprüfen muss, aber das Argument zählt nicht ;-) Im Übrigen ist das Selberschreiben eines Full-Blown oder sogar nur eines Minimum Netzwerk-Stacks eine Höllenaufgabe. Das sieht am Anfang leicht aus, macht auch Spaß. Aber danach verbringt man nur noch Zeit mit Debuggen via Wireshark o.ä. um die verfluchten (aber dennoch genialen) TCP Sequenz und Acknummern hinzubekommen bspw. Oder um die nötigen TCP MSS Optionen korrekt zu setzen oder (viel schlimmer) Optionen von einem anderen undefinierten Netzwerk-Stack zu erkennen und anzuwenden.
Wenn Du mit Stack das Protokollformat meinst, das läßt sich nicht vermeiden, daß das bei den einzelnen Interfaces völlig unterschiedlich ist. Sonst gäbe es ja unterschiedliche Interfaces nicht. Du mußt also jedes Protokoll für sich parsen, um die Informationen auszulesen. Wenn Du ein Protokoll aber nur transportieren willst, ohne den Inhalt auszuwerten, dann definiere einfach ein Universalpaket, welches beliebige Paketlängen verpacken kann. Z.B. beim CAN-Bus kann man immer nur 8 Byte versenden. Um darin andere Pakete einzupacken, reserviert man das 1. Byte als Kennzeichen für ein Fremdpaket und das 2. als Paketzähler. Jeder CAN-Frame kann dann noch bis zu 6 Byte Fremddaten enthalten. Und dann soviel CAN-Pakete basteln, wie nötig. Man sollte aber nicht ein schon verpacktes Protokoll nochmal verpacken. Wäre quasi so, wie SPI in Software über nen PCF8574 nachzubilden (dauert ewig). Peter
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.