Forum: Mikrocontroller und Digitale Elektronik Protokoll Stack Auswertung


von Franz (Gast)


Lesenswert?

Hallo zusammen,

ich habe eine Prinzipfrage zur Auswertung eines beliebigen Protokolls 
(ohne RTOS),  das in Schichten Aufgebaut ist,Physical -> Data Link -> 
Network usw. (zb. TCP)
Das Ergebnis der Auswertung jeder Schicht wird die in einem eigenen 
Buffer abgespeichert auf die die nächste Schicht zugreift oder wird ein 
und derselbe Buffer von allen Layern bearbeitet?

Wie ich mir das so Vorstelle am Beispiel einer seriellen uart 
Schnittstelle als Physical Layer:

1. (Physical Layer)
alle ankommenden Bytes werden in einen Ringbuffer geschrieben (ISR)
2. (Data Link Layer, Network Layer)
Funktion untersucht alle neuen Bytes und Schreibt das zusammenhängende 
Protokoll Frame in einen Linearbuffer, wenn die Checksumme, Adresse etc. 
stimmt, hier wird oft ein ACK gefordert, jetzt müsste diese Funktion 
also auch in der ISR abgearbeitet werden umd Zeitgerecht zu Antworten 
oder sehe ich das falsch? Je nach Fuktionsumfang könnte das aber relativ 
Zeitintensiv werden was in einer ISR dann nicht so toll ist.
3. (Transport Layer)
Funktion extrahiert die Nutzdaten aus dem Protokoll Frame und kopiert 
diese in einen weiteren Ringbuffer welcher dann aus den reinen Nutzdaten 
Frames (APDU) besteht.
4.
Zeitlich unkritische Abarbeitung der Daten


Meine Frage ist jetzt wie weit bin ich mit meiner Vorstellung von der 
Realität entfernt bzw. wie wird so etwas normal gemacht?
Problematisch für mich ist der Zeitliche Ablauf um keine Daten zu 
verlieren bzw. Bufferüberläufe zu verhindern und dennoch Zeit für die 
Restliche Applikation zu haben....

Danke schonmal für den Versuch mich aufzuklären :) Bin auch dankbar 
dafür wenn mir jemand sagen kann wo man sich über solche Sachen schlau 
machen kann, hab nicht wirklich was gefunden bzw. weiß ich nicht wonach 
ich suchen soll, unter Protokoll Stack Entwicklung finde ich nur sehr 
Allgemein gehaltene Infos bzw Infos.

Gruß
Franz

von Franz (Gast)


Lesenswert?

Keiner der irgendwelche Anregungen für mich hat, oder hab ich mich 
unklar Ausgedrückt? Bitte fragen!

von Tillomar S. (tillomar)


Lesenswert?

Du sprichst hier einen Sonderfall an -- Du erwartest auf einem PhyLayer, 
der per se keine Pakete unterstützt, ebensolche...

Dein Hauptproblem ist also erst einmal, möglichst effizient die Daten 
der einzelnen Pakete voneinander zu trennen, damit sie dann paketweise 
weiterverarbeitet, gespeichert, quittiert, usw. werden können.

Falls das auf Grund der Struktur der Daten möglich ist, empfiehlt es 
sich, die Paketierung der Streamdaten schon im Interrupt zu machen, z.B. 
durch eine Zustandsmaschine; die fertigen Pakete werden dann nach oben 
an den Stack weitergereicht. Dadurch wird die Interrupt-Rate erheblich 
verringert. Ist allerdings die Erkennung der Paketgrenzen bereits 
aufwendig, dann ist ein (hoch-priorer) Task besser geeignet.

Ansonsten gibt es beide genannten Methoden, die Daten durch einen 
Protokoll-Stack durchzureichen: Jeweils weiterkopieren, oder im 
originalen Puffer der untersten Schicht belassen und darin 
weiterarbeiten.

Die Kopier-Varianten hat den offensichtlichen Nachteil, daß die Daten 
jeweils kopiert werden müssen -> Speicher- und Zeitaufwand. Der 
Hauptvorteil ist, daß der Datenumfang von Schicht zu Schicht abnimmt -- 
normalerweise muß man ja hauptsächlich die Nutzlast der 
darunterliegenden Schicht übernehmen. Müssen nun in einer Schicht 
mehrere Pakete gepuffert werden, dann kann der reduzierte Speicherbedarf 
wesentlich sein.

Quittungen sollten immer in dem Level des Stacks erzeugt werden, zu dem 
sie gehören; oft genug gehören sie ja auch zu den Puffermechanismen 
dieser Schicht.

So long,
Tillomar

von Franz (Gast)


Lesenswert?

Danke für deine Erklärung, hilft mir schon mal weiter :)

Diesen Teil verstehe ich nicht ganz, was genau ist damit gemeint?

Tillomar Sondermann schrieb:
> Quittungen sollten immer in dem Level des Stacks erzeugt werden, zu dem
> sie gehören; oft genug gehören sie ja auch zu den Puffermechanismen
> dieser Schicht.

Gibt es vielleicht einfache Beispiele wo so eine Stack Implementierung 
umgesetzt wird?

von AVR-Frickler (Gast)


Lesenswert?

Es gibt auch noch die Möglichkeit für jeden Frame, Speicher dynamisch zu 
allokieren. Die Frames dann per verkettete Liste durch die Schichten zu 
reichen.

Gerade auf einem µC sollte man da natürlich den Speicherverbrauch im 
Auge behalten. Sollte man feststellen das nicht mehr genügend Speicher 
für den nächsten Frame zur Verfügung steht sollte man die Übertragung am 
besten auf den Physical Layer unterbinden, bei RS232 könnte man z.B. 
Handshake-Leitungen nutzen.

Bietet der Physical Layer keine solche Möglichkeit kann man versuchen 
das auf eine der nächsten Layer zu verschieben, bei I2C z.B. die 
eingehenden Pakete mit NAK beantworten.

von Tillomar S. (tillomar)


Lesenswert?

> Diesen Teil verstehe ich nicht ganz, was genau ist damit gemeint?
>
> Tillomar Sondermann schrieb:
>> Quittungen sollten immer in dem Level des Stacks erzeugt werden, zu dem
>> sie gehören; oft genug gehören sie ja auch zu den Puffermechanismen
>> dieser Schicht.

Eine Quittung ist üblicherweise nicht Bestandteil der Nutzlast; daher 
muß sie im Rahmen transportiert werden. Dieser Rahmen ist aber für die 
darunterliegende Schicht die Nutzlast -> ergo darf eine Schicht niemals 
durch eine andere hindurchgreifen, auch wenn sie das in einem 
NoCopy-Stack prinzipiell könnte.

> Gibt es vielleicht einfache Beispiele wo so eine Stack Implementierung umgesetzt 
wird?

Sorry, muß ich passen -- ich liebe komplizierte Beispiele... :)
Scherz beiseite, ich habe gerade nix zur Hand, was als Beispiel geeignet 
wäre UND was ich herausgeben dürfte.
Mögen die edlen Mitstreiter in die Bresche springen. ;)

So long,
Tillomar

von Franz (Gast)


Lesenswert?

AVR-Frickler schrieb im Beitrag #3124973:
> Die Frames dann per verkettete Liste durch die Schichten zu
> reichen.

Wie genau kann ich mir das Vorstellen?


Tillomar Sondermann schrieb:
> -> ergo darf eine Schicht niemals
> durch eine andere hindurchgreifen, auch wenn sie das in einem
> NoCopy-Stack prinzipiell könnte.

Ich nehme an das Selbe gilt für Prüfsummen Auswertung etc.?

Warum eigentlich? Um die "Norm" einzuhalten oder gibt es da auch 
technische Gründe, auf Anhieb würde mir da nichts einfallen was dagegen 
spricht, im Gegenteil teilweise könnte man sogar fühzeitig illegale, 
defekte Frames aus dem Verkehr ziehen?

Tillomar Sondermann schrieb:
> Mögen die edlen Mitstreiter in die Bresche springen. ;)

ich hoffe :)

von Franz (Gast)


Lesenswert?

Franz schrieb:
> AVR-Frickler schrieb im Beitrag #3124973:
>> Die Frames dann per verkettete Liste durch die Schichten zu
>> reichen.
>
> Wie genau kann ich mir das Vorstellen?

schon was gefunden :)

http://de.wikibooks.org/wiki/C-Programmierung:_Verkettete_Listen

von Franz (Gast)


Lesenswert?

Allerdings verstehe ich noch nicht wie man damit Frames durch die 
Schichten reicht?

von Tillomar S. (tillomar)


Lesenswert?

Franz schrieb:
> Allerdings verstehe ich noch nicht wie man damit Frames durch die
> Schichten reicht?

Und ich auch nicht.

Ein verkettete Liste benötigt man dann, wenn wenn die Menge oder 
insbesondere die Reihenfolge von Objekten jederzeit mit geringem Aufwand 
ändern können muß.

Diese Anwendung sehe ich hier nicht; freilich kann sich die Anzahl der 
wartenden Buffer ändern, normalerweise aber nicht die Reihenfolge, daher 
wäre ein Array mit Buffern, sowie deren Verwaltung mit Pointern oder 
Indices effizienter.

So long,
Tillomar

von THaala (Gast)


Lesenswert?

Ich war jahrelang in einer Firma für den Protokollrahmen verantwortlich 
und habe auch meine Diplomarbeit in diesem Zusammenhang gemacht.

Unter dem Begriff verteckt sich eben ziemlich genau die Maschinerie Die 
Du selbst ganz oben beschrieben hast.

Einer der Vorteile war, das sich ca. 90 % aller seriellen Protokoll auf 
diese Weise zur Applikation hin gleich verhielten und ein Ko-Prozessor 
auf 8031-Basis auf verschiedenen Steckkarten sich für einem Zoo von 
Rechnern für PC, SUN, 19-Zoll Bussysteme usw. skalieren ließ.

Die meisten Feldbussysteme kamen damit Klar: z.B. BITBUS, DIN66348, 
MODBUS, SEAB, DIN19244 und eine weitere Menge die ich inzwischen 
vergessen habe...

Einige Protokolle wie etwa Profibus hatten damit auch Ihre 
Schwierigkeiten, da Sie an das reduzierte OSI - Modell (1,2 -7) 
Angepasst sind und seperate Abfragepunkte bereitstellen sollen, die 
sozusagen als "schnelle" Messwertanfrage dienen sollten, die Messwerte 
beiinhalten.

CAN z.B. wäre für einen Einsatz in einem voll ausdekodierten OSI-Modell 
sicher fehl am Platz. Es sei den als Visualisierungszentrale.

Generell sind Protoklle ungeeignet, die quasi als Antwort auf eine 
Aktion die Schicht 7 erledigen soll, Daten erwarten. Z.B. reine Punkt zu 
Punkt Protokolle sind dafür ungeeignet.

Gruß Thilo

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

Tillomar Sondermann schrieb:
> Diese Anwendung sehe ich hier nicht; freilich kann sich die Anzahl der
> wartenden Buffer ändern, normalerweise aber nicht die Reihenfolge, daher
> wäre ein Array mit Buffern, sowie deren Verwaltung mit Pointern oder
> Indices effizienter.

Über die konkrete Anwendung hat Franz ja noch nicht viel geschrieben. 
Wenn man einen festen Puffer für alle Schichten als das eine Ende 
ansieht, wollte ich nur das andere Ende aufzeigen.

Franz schrieb:
> Allerdings verstehe ich noch nicht wie man damit Frames durch die
> Schichten reicht?

1. Layer
Ein ganze normale serielle Verbindung mit 1 Starbit 8 Datenbits 1 
Stopbit. Womit das Protokoll eigentlich schon spezifiziert ist.

2. Layer
Hier kommt jetzt deine ISR ins Spiel, hier müssen je nach Protokoll 
schon die ersten Daten ausgewertet werden.

a. Feste Framelänge
a-1. Speicher in der ISR reservieren
a-2. die main-Schleife sorgt von alleine dafür das immer ein 
Listenelement verfügbar ist

b. Das Protokoll sieht vor, dass in den ersten Bytes mitgeteilt wie viel 
Bytes folgen (Daten + Prüfsumme). Die ersten Bytes müssten dann in einem 
kleinen Puffer zwischengespeichert werden.
b-1. Speicher in der ISR reservieren
b-2. Über globale Variablen der main-Schleife mitteilen wie viel 
Speicher reserviert werden soll.

Sobald die Daten vollständig sind und eine eventuell vorhandene 
Prüfsumme stimmt, bestätigt die ISR den Datenempfang und hängt das 
Listenelement in die Liste ein oder fordert zum erneuten senden auf.

3. Layer
Hier gibt es nun mehrere Möglichkeiten, die main-Schleife prüft selbst 
ständig ob ein neues Listenelement verfügbar ist oder die ISR teilt über 
weitere globale Variablen mit dass neue Daten verfügbar sind.

Was in der main-Schleife mit den Daten nun passiert bleibt dir 
überlassen, entweder hast du auch hier noch mehrere Layer oder im 
einfachsten Fall eine einzelne Funktion welche die Daten auswertet.

Franz schrieb:
> Gibt es vielleicht einfache Beispiele wo so eine Stack Implementierung
> umgesetzt wird?

Einfache Beispiele habe ich leider auch nicht zu bieten, du kannst aber 
mal versuchen den IP-Stack in Ulrich Radigs Webserver zu verstehen.
http://www.ulrichradig.de/home/index.php/avr/eth_m32_ex

Der Stack verwendet einen globalen Puffer für alle Schichten.

von Tillomar S. (tillomar)


Lesenswert?

Ich glaube, wir haben den TO überfahren... ;)

So long,
Tillomar

von Franz (Gast)


Lesenswert?

Fast :) Nein aber ich muss die ganzen Infos erst aufnehmen, verarbeiten 
und dann etwas sitzen lassen um nacher die richtigen Fragen stellen zu 
können ;)
Stehe hier ganz am Anfang und will nur das Prizip mit Bezug auf die 
praktische Umsetzung verstehen. Dank euerer Hilfe bin ich auch schon 
wesentlich vorangekommen :)


M. K. schrieb:
> b-1. Speicher in der ISR reservieren
> b-2. Über globale Variablen der main-Schleife mitteilen wie viel
> Speicher reserviert werden soll.

warum muss der main Schleife mittgeteilt werden wie viel Speicher 
reserviert werden soll wenn dieser doch in der ISR ermittelt und 
reserviert wird? Denke du meinst hier den Pointer auf den in der ISR 
reservierten und befüllten Speicherbereich?


M. K. schrieb:
> Einfache Beispiele habe ich leider auch nicht zu bieten, du kannst aber
> mal versuchen den IP-Stack in Ulrich Radigs Webserver zu verstehen.
> http://www.ulrichradig.de/home/index.php/avr/eth_m32_ex

Danke für den Tip, hat mir sehr geholfen!


AVR-Frickler schrieb im Beitrag #3124973:
> Es gibt auch noch die Möglichkeit für jeden Frame, Speicher dynamisch zu
> allokieren. Die Frames dann per verkettete Liste durch die Schichten zu
> reichen.

Hab das jetzt so verstanden:
es gibt für jede Schicht eine Queue (verkettete Liste) und jedes Frame 
wird dann von queue zu queue weitergereicht....also in der unteren 
Schicht ausgehängt und in der nächsten Schicht nach verarbeitung wieder 
eingehängt. Vorteil hier ist das einzelne Frames nicht zwingend der 
Reihe nach weiter bearbeitet werden müssen sonder je nach priorität auch 
dazwischen entnommen werden können etc. Sind die Daten nicht regelmäßig 
segmentiert ist das für Layer 4 eigentlich fast zwingend erfoderlich.
Hab ich das soweit richtig versanden?

Nächste Frage :)
Die ankommenden Frames können aus meiner Sicht in 2 unterschiedlichen 
Varianten auf Schicht 7 "enden"
Variante1: Frame löst direkt eine Funktion aus die aus den enthaltenen 
Daten etwas macht.

Variante2: FrameDaten werden in einer Queue gepuffert und die Anwendung 
schaut dort regelmäßig nach und verarbeitet sie dann bei Gelegenheit.

Im Beispiel von Ulrich Radig wird soweit ich das verstanden habe 
Variante1 verwendet und breits in Schicht 3 die dazugehörige Funktion 
verlinkt.

Generell werden die Frames in Schicht 3 ja auf die einzelnen 
registrierten Adressen, Ports etc. aufgeteilt. Heißt das dann, das es 
für jeden registrierten Port etc. eine eigene Queue gibt? Würde bedeuten 
das alle darauf folgenden Schichten für jeden Port etc. separat 
existieren, also zb. mehrere Schicht 4 Elemente parallel, kann das sein?

Wenn Variante2 verwendet wird muss in Schicht 3 eigentlich auch keine 
Funktion zugeordnet werden oder?

Gar nicht mal so einfach, wo lernt man so etwas im Normalfall? Verstehe 
nicht ganz warum es hier keine Informationen zu finden gibt obwohl das 
ja eine sehr verbreitete Methode ist!?

Danke nochmal für eure Hilfe :)

von Tillomar S. (tillomar)


Lesenswert?

Franz schrieb:
> warum muss der main Schleife mittgeteilt werden wie viel Speicher
> reserviert werden soll wenn dieser doch in der ISR ermittelt und
> reserviert wird? Denke du meinst hier den Pointer auf den in der ISR
> reservierten und befüllten Speicherbereich?

Hängt davon ab, wie man es implementiert.
Ich würde einen Pool-Service einrichten, der auch aus dem interrupt 
aufrufbar ist, und Funktionen zum Anfordern und freigeben von Puffern 
zur Verfügung stellt. Dann braucht die ISR das fertige Paket nur noch in 
einen frisch angforderten Puffer zu stecken, und einen Descriptor für 
diesen Puffer in die Warteschlange einzuhängen. Kommt main() mal wieder 
vorbei, ist gleich erkennbar, daß da wieder was wartet. Am Ende wird der 
Puffer mit dem gleichen Service zurückgegeben, oder man behält ihn 
gleich für die Antwort -- das kann in jeder Schicht geschehen, nicht nur 
in 7.

Franz schrieb:
> Hab das jetzt so verstanden:
> es gibt für jede Schicht eine Queue (verkettete Liste) und jedes Frame
> wird dann von queue zu queue weitergereicht....also in der unteren
> Schicht ausgehängt und in der nächsten Schicht nach verarbeitung wieder
> eingehängt. Vorteil hier ist das einzelne Frames nicht zwingend der
> Reihe nach weiter bearbeitet werden müssen sonder je nach priorität auch
> dazwischen entnommen werden können etc.

Natürlich kannst Du einen Puffer aus einer Queue aushängen, um ihn in 
der Queue der nächsten Schicht wieder einzuhängen -- aber Du kannst auch 
mehrere Queues gleichzeitig über den gleichen Satz von Puffern legen, 
wenn Du mehr als einen Zugriffspfad (z.B. Sortierung) benötigst.

Franz schrieb:
> Sind die Daten nicht regelmäßig
> segmentiert ist das für Layer 4 eigentlich fast zwingend erfoderlich.
> Hab ich das soweit richtig versanden?

Sorry, daß verstehe ich jetzt nicht...
Meinst Du segmentiert oder fragmentiert? Bist Du jetzt bei TCP/IP?

Franz schrieb:
> Im Beispiel von Ulrich Radig wird soweit ich das verstanden habe
> Variante1 verwendet und breits in Schicht 3 die dazugehörige Funktion
> verlinkt.

Nennt man Callbacks...

> Generell werden die Frames in Schicht 3 ja auf die einzelnen
> registrierten Adressen, Ports etc. aufgeteilt. Heißt das dann, das es
> für jeden registrierten Port etc. eine eigene Queue gibt? Würde bedeuten
> das alle darauf folgenden Schichten für jeden Port etc. separat
> existieren, also zb. mehrere Schicht 4 Elemente parallel, kann das sein?

Jain.
Das Problem ist natürlich, genügend viele bzw. differenzierte "Ausgänge" 
aus dem Stack zu haben. Deshalb läuft das normalerweise durch den 
Socket-Layer (was jetzt aber kein Stack-Layer ist ;), bei dem die 
Applikation Sockets öffnet (wie File-Handles); dadurch weiß der Socket 
Layer dann, wem er ein Packet überreichen muß. Ist mit echten Threads 
natürlich wesentlich eleganter zu implementieren...

So long,
Tillomar

von Franz (Gast)


Lesenswert?

Tillomar Sondermann schrieb:
> Sorry, daß verstehe ich jetzt nicht...
> Meinst Du segmentiert oder fragmentiert? Bist Du jetzt bei TCP/IP?

fragmentiert, also Schicht 4 baut ja evtl. aus mehreren Paketen einen 
zusammenhängenden Datenstrom für die höheren Schichten und diese Pakete 
müssen ja nicht in der richtigen Reihenfolge daher kommen, könnten 
zwischenzeitlich ja Pakete für einen anderen "Port" sein.

Den Übergang von Schicht 3 zu 4 hab ich noch nicht richtig verstanden, 
Schicht 3 teilt die Frames ja auf die einzelnen "Ports" auf d.h. ab hier 
verläuft der weg der einzelnen Frames ja auseinander und muss 
zwangsläufig separat behandelt werden?

von Tillomar S. (tillomar)


Lesenswert?

Franz schrieb:
> fragmentiert, also Schicht 4 baut ja evtl. aus mehreren Paketen einen
> zusammenhängenden Datenstrom für die höheren Schichten und diese Pakete
> müssen ja nicht in der richtigen Reihenfolge daher kommen, könnten
> zwischenzeitlich ja Pakete für einen anderen "Port" sein.

Soweit richtig, nur hat das nichts mit Fragemtierung zu tun, denn die 
findet von Schicht 3 zur Schicht 2 statt, bzw. das Reassembly in Schicht 
3.

Du must die Ebenen richtig unterscheiden:

Ebene 3 macht empfangsseitig das Reassembly, d.h. fügt fragemntierte 
IP-Pakete wieder zusammen.

Ebene 4 bekommt vollständige TCP-Pakete, diese können aber ebenfalls 
noch in der falschen Reihenfolge sein; sie werden im Sliding Window 
Buffer zu einem vollständigen Datenstrom assembliert.

Ob die Daten dann in einen Stream-Puffer umkopiert werden, oder in den 
TCP-Paket-Puffern verbleiben, bis der Inhalt gelesen wurde, ist 
implementierungsabhängig.

Franz schrieb:
> Den Übergang von Schicht 3 zu 4 hab ich noch nicht richtig verstanden,
> Schicht 3 teilt die Frames ja auf die einzelnen "Ports" auf d.h. ab hier
> verläuft der weg der einzelnen Frames ja auseinander und muss
> zwangsläufig separat behandelt werden?

Nicht zwangsläufig. Die Implementierung des Sliding Window Buffer könnte 
durchaus auch als zusätzliche Schicht auf den normalen Puffer-Pool 
gelegt werden. Ich würde allerdings wohl auch zu jedem Port eine Queue 
machen.

TCP ist ja verbindungsorientiert, und die Verbindung hat einen Besitzer; 
im Zweifelsfall kommt der Speicher aus dessen Kontext.

Gruß,
Tillomar

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

Tillomar Sondermann schrieb:
> Ich glaube, wir haben den TO überfahren... ;)
>
> So long,
> Tillomar

Franz schrieb:
> Fast :) Nein aber ich muss die ganzen Infos erst aufnehmen, verarbeiten
> und dann etwas sitzen lassen um nacher die richtigen Fragen stellen zu
> können ;)

Hehe 6 Tage um durch Ulrich Radigs Webserver durchblicken braucht man 
wirklich. Wie gut das ich ihm nicht den Link zu Ethersex gepostet habe.

Tillomar Sondermann schrieb:
> Franz schrieb:
>> Hab das jetzt so verstanden:
>> es gibt für jede Schicht eine Queue (verkettete Liste) und jedes Frame
>> wird dann von queue zu queue weitergereicht....also in der unteren
>> Schicht ausgehängt und in der nächsten Schicht nach verarbeitung wieder
>> eingehängt. Vorteil hier ist das einzelne Frames nicht zwingend der
>> Reihe nach weiter bearbeitet werden müssen sonder je nach priorität auch
>> dazwischen entnommen werden können etc.
>
> Natürlich kannst Du einen Puffer aus einer Queue aushängen, um ihn in
> der Queue der nächsten Schicht wieder einzuhängen -- aber Du kannst auch
> mehrere Queues gleichzeitig über den gleichen Satz von Puffern legen,
> wenn Du mehr als einen Zugriffspfad (z.B. Sortierung) benötigst.

Ich nicht ob ich Tillomar richtig verstanden habe, wahrscheinlich meinst 
du aber dasselbe was ich gleich beschreibe.

Anstelle von mehreren Listen kannst du auch wirklich nur eine einzige 
verwenden und mehrere Zeiger in die Liste zeigen lassen. Du kannst dir 
für jede Schicht einen Zeiger machen.

Vielleicht wird es etwas klarer wenn ich dir mal eine Struktur für ein 
Listenelement zeige.
1
typedef struct {
2
        uint8_t     state       // Status des Listen-Elements
3
        uint8_t     fromLayer   // Aus welcher Schicht stammen die Daten
4
        uint8_t     toLayer     // Für welche Schicht sind die Daten
5
       uint16_t     bufferlen   // Länge des Zeichenpuffers
6
        uint8_t*    buffer;     // Zeiger auf den Zeichenpuffer
7
    struct item*    next;       // Zeiger auf das nächste Element.
8
} item;

Das wichtigste: Wie du siehst enthält die Struktur einen Zeiger auf den 
Datenspeicher (buffer) diesen Zeiger kannst du natürlich in mehreren 
Listenelementen verwenden. Wenn eine Schicht die Daten an die nächste 
Schicht weitergeben möchte erzeugt sie ein neues Listenelement und setzt 
den Zeiger (buffer) auf dieselbe Adresse des Datenspeichers der in 
dieser Schicht verarbeitet wurde.

Ich habe der Struktur noch die Elemente state, fromLayer und toLayer 
gegeben.

state kann verwendet werden wenn du die verwaltung der Liste zentral 
abwickeln möchtest, z.B durch eine Art Garbage-Collector. Eine andere 
Möglichkeit besteht darin dass jede Schicht ihre eigenen Listenelemente 
selbst aus der Liste entfernt. Allerdings muss man hier höllisch 
aufpassen die Liste nicht zu zerstören, wenn Schichten sich in der Liste 
'überholen' können. Auch mit der ISR muss man aufpassen, dass das 
ein-/aushängen atomar passiert.

fromLayer und toLayer kann verwendet werden um in den Schichten 
entscheiden zu können welche Richtung die Pakte nehmen, so kannst du 
z.B. bei TCP/IP die Datenspeicher solange weiter verwenden bis eine 
Transaktion abgeschlossen ist.

Wenn du dir den Datenfluss in Ulrich Radigs Webserver anschaust wirst du 
sehen das er vom Ethernet-Controller immer ein Ethernet-Frame mit 1500 
Bytes ausliest und dann komplett durch alle Schichten schiebt und beim 
antworten teilweise durch alle Schichten durchgreift und dann direkt mit 
dem Ethernet-Controller arbeitet. Das wurde weiter oben schon erwähnt 
das dies nicht gerade optimal ist.

Ein weiterer Nachteil dabei ist, wenn eine Schicht sehr lange braucht um 
die Pakete zu verarbeiten, kann es schon  mal passieren das trotz 8Kb 
Puffer im Ethernet-Controller Pakete verloren gehen können.

von Franz (Gast)


Lesenswert?

M. K. schrieb:
> Hehe 6 Tage um durch Ulrich Radigs Webserver durchblicken braucht man
> wirklich.

Leider steht wie bei jedem Hobby immer zu wenig Zeit dafür zur Verfügung 
;)

M. K. schrieb:
> Anstelle von mehreren Listen kannst du auch wirklich nur eine einzige
> verwenden und mehrere Zeiger in die Liste zeigen lassen. Du kannst dir
> für jede Schicht einen Zeiger machen.

OK hab ich verstanden aber das wird doch ziemlich unübersichtlich wenn 
in ein und der selben Liste alle Schichten gemischt sind und wie du 
selbst schreibst muss man dann höllisch aufpassen, da sind getrennte 
Listen schon übersichtlicher und unproblematischer oder nicht?

M. K. schrieb:
> fromLayer und toLayer kann verwendet werden um in den Schichten
> entscheiden zu können welche Richtung die Pakte nehmen, so kannst du
> z.B. bei TCP/IP die Datenspeicher solange weiter verwenden bis eine
> Transaktion abgeschlossen ist.

das verstehe ich nicht?

Tillomar Sondermann schrieb:
> Nicht zwangsläufig. Die Implementierung des Sliding Window Buffer könnte
> durchaus auch als zusätzliche Schicht auf den normalen Puffer-Pool
> gelegt werden.

wäre das dann nicht auch ein durchgreifen durch die Schicht? Schicht 4 
sieht doch nur mehr die Pakete für den entsprechenden "Port" und muss 
daher ja für eben alle vorkommenden "Ports" separat behandelt werden?

Tillomar Sondermann schrieb:
> Ob die Daten dann in einen Stream-Puffer umkopiert werden, oder in den
> TCP-Paket-Puffern verbleiben, bis der Inhalt gelesen wurde, ist
> implementierungsabhängig.

Und das wird bei der Registrierung des "Ports" bereits festgelegt oder? 
Sprich bei ankommenden Frames weiß ich ab Schicht 3 ob direkt eine 
Funktion ausgeführt wird oder ob die Daten in einem Puffer landen.

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

Franz schrieb:
> OK hab ich verstanden aber das wird doch ziemlich unübersichtlich wenn
> in ein und der selben Liste alle Schichten gemischt sind und wie du
> selbst schreibst muss man dann höllisch aufpassen, da sind getrennte
> Listen schon übersichtlicher und unproblematischer oder nicht?

Einfacher wird es sicher sein, der Verwaltungsaufwand ist halt etwas 
höher.
Wie gesagt jede Schicht kann ihre 'eigenen' Listenelemente nur als 
bearbeitet markieren. Am Ende der main-Schleife gehst du einmal die 
komplette Liste durch und löschst dann alle markierten Elemente. Das 
meinte ich mit Garbage-Collector.

Franz schrieb:
> M. K. schrieb:
>> fromLayer und toLayer kann verwendet werden um in den Schichten
>> entscheiden zu können welche Richtung die Pakte nehmen, so kannst du
>> z.B. bei TCP/IP die Datenspeicher solange weiter verwenden bis eine
>> Transaktion abgeschlossen ist.
>
> das verstehe ich nicht?

Bei TCP/IP musst du ja nicht nur von Schicht 0 rauf auf Schicht 4 sonder 
auch wieder zurück um eine Bestätigung (Ack) zu senden das die Daten 
korrekt empfangen wurden. Dazu werden auch Informationen aus dem 
empfangen Paket benötigt.
Es muss das richtige ACK zum passenden SEGMENT gesendet werden. In dem 
oben verlinkten Webserver wird einfach in der letzten Schicht ein 
komplettes Paket geschnürt und direkt dem Ethernet-Controller übergeben. 
Die anderen Schichten bekommen davon also nichts mit.

Wenn du der Funktion für Schicht 3 nun einfach Daten überreichst und 
sagst '''mach''', stellt sich danach die Frage und wohin jetzt mit dem 
Paket? Ist das jetzt ein Paket für Schicht 4 oder versucht Schicht 4 nun 
das letzte Paket zu beantworten?
Bei UDP-Verbindungen wirst du dies allerdings nicht benötigen, weil hier 
keine Bestätigung gesendet wird.

Franz schrieb:
> Tillomar Sondermann schrieb:
>> Ob die Daten dann in einen Stream-Puffer umkopiert werden, oder in den
>> TCP-Paket-Puffern verbleiben, bis der Inhalt gelesen wurde, ist
>> implementierungsabhängig.
>
> Und das wird bei der Registrierung des "Ports" bereits festgelegt oder?
> Sprich bei ankommenden Frames weiß ich ab Schicht 3 ob direkt eine
> Funktion ausgeführt wird oder ob die Daten in einem Puffer landen.

Dies hat mit Ports erst einmal nichts zu tun, das ist eine Grundlegende 
Entscheidung die du beim Programmieren des Stacks triffst.

In Ulrich Radigs Webserver hast du keine andere Möglichkeit als die 
Daten umzukopieren, weil das nächste Paket den Puffer gnadenlos 
überschreibt.
Mit der Liste kannst du dir das ersparen, du kannst die Daten solange 
halten bis dir der RAM oder die Anzahl der reservierten Puffer ausgeht.

von Franz (Gast)


Lesenswert?

Ah ok klingt logisch, danke :)

Wenn ich jetzt der Einfachheit halber alles in eine eigene Queue packe 
dann gibt es ab Schicht 3 aber für jeden "Port" eine eigene Queue und 
Schicht 4 muss jede dieser Queues durchlaufen?

Muss jetzt mal die callback Geschichte genauer unter die Lupe nehmen....

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.