12.5. Zuverlässigkeit – Sequenzen, ACKs, erneute Übertragungen¶
Die Framing-Schicht erkennt Beschädigungen mithilfe ihrer CRCs. Die Zuverlässigkeitsschicht macht aus „erkannter Beschädigung“ ein „die Anwendung sieht niemals fehlerhafte Daten“, indem sie erneute Übertragungen aushandelt, sobald ein Paket nicht intakt ankommt.
12.5.1. Sequenznummern¶
Jeder Paket-Header trägt eine ein Byte große Sequenznummer, separat für jede Übertragungsrichtung. Der Sender erhöht den Zähler vor dem Senden; der Empfänger prüft, dass die Sequenz jedes empfangenen Pakets der vorherigen plus eins entspricht (modulo 256).
Drei Dinge können beim Empfänger anstelle eines sauberen, reihenfolgegetreuen Pakets auftauchen:
Die erwartete Sequenznummer mit gültigem CRC. Das Paket wird an die nächste Schicht weitergereicht.
Die erwartete Sequenznummer mit fehlerhaftem CRC. Der Empfänger verwirft das Paket und sendet (sofern ACKs ausgehandelt sind) ein NAK, das eine erneute Übertragung anfordert.
Eine Sequenznummer, die um eins höher als erwartet ist, mit gültigem CRC. Der Empfänger weiß, dass das vorherige Paket verloren gegangen ist; er sendet ein NAK, das auf die fehlende Sequenz verweist, und legt das neue Paket beiseite.
Der Duplikatfall (eine erneute Übertragung, die ankommt, nachdem das Original schließlich doch durchgekommen ist) wird durch Abgleich mit dem erwarteten Zähler behandelt: Liegt die Sequenz hinter der erwarteten, handelt es sich um ein Duplikat, und der Empfänger verwirft es, nachdem er das ACK gesendet hat, das der Sender beim ersten Mal offensichtlich nicht erhalten hatte.
12.5.2. ACK und NAK¶
Zwei Flag-Bits im Paket-Header tragen den Zuverlässigkeitsverkehr selbst:
ACK_REQgesetzt auf einem ausgehenden Paket bedeutet „Ich möchte eine Bestätigung zurück.“ Datenpakete setzen dies normalerweise; Status-Pings und einmalige Ereignisse möglicherweise nicht.ACKgesetzt auf einem Paket bedeutet „dieses Paket ist die Bestätigung für die Sequenznummer im Header.“ Es trägt keine eigene Nutzlast.NAKgesetzt bedeutet „dieses Paket weist ein vorheriges zurück“ – in der Regel wegen eines fehlerhaften CRC oder einer Lücke in der Sequenznummerierung. Der Header weist den Sender darauf hin, welche Sequenz erneut zu übertragen ist.
Der Sender führt eine Stop-and-Wait-Schleife aus: Er überträgt ein Paket, das eine Bestätigung erfordert, und wartet dann auf das passende ACK (oder NAK), bevor er das nächste sendet. Das Modell mit nur einem Paket in Übertragung hält den Senderzustand begrenzt – ein paar hundert Byte auf den kleinsten Kameras – und passt zur Rolle des Protokolls als Steuerkanal zwischen zwei Endpunkten statt als durchsatzoptimierte Pipe. Bei einem NAK überträgt der Sender dasselbe Paket erneut mit gesetztem RTX-Flag, damit der Empfänger weiß, dass es sich um einen erneuten Versuch handelt.
12.5.3. Zeitsteuerung der erneuten Übertragung¶
Trifft innerhalb des Retransmit-Timeouts weder ein ACK noch ein NAK ein, überträgt der Sender das in Übertragung befindliche Paket von sich aus erneut. Der Timeout liegt standardmäßig bei 500 ms und verdoppelt sich bei jedem aufeinanderfolgenden erneuten Versuch (1 s, 2 s, …). Nach der konfigurierten Anzahl erneuter Versuche – standardmäßig drei – gibt der Sender auf und meldet der Anwendung einen Transportfehler.
Die Verdopplung des Timeouts ist das übliche Muster des exponentiellen Backoffs. Ein kurzer erster Timeout fängt verlorene Pakete schnell ab; die Verdopplung sorgt dafür, dass ein für einige hundert Millisekunden beschäftigter Host keine Flut von Duplikaten auslöst, die die Last weiter erhöhen.
12.5.4. Zuverlässigkeit konfigurieren¶
Beide Enden können Teile der Zuverlässigkeitsschicht im gegenseitigen Einvernehmen abschalten, wenn die Anwendung es sich leisten kann, Daten zu verlieren:
protocol.init(ack=False)deaktiviert die ACKs pro Paket. Der Sender feuert und vergisst; der Empfänger liefert, was ankommt. Gut für das Streamen von Sensordaten, bei denen eine veraltete Probe akzeptabel ist.protocol.init(seq=False)schaltet die Verfolgung der Sequenznummern ab, was auch das Abschalten der ACKs impliziert. Nur auf vollkommen zuverlässigen Transporten sinnvoll.protocol.init(crc=False)schaltet die CRC-Validierung ab, lässt aber den Rest des Framings intakt. Nur dann sinnvoll, wenn der Transport selbst robust genug ist, dass keine CRC-Fehler auftreten.
Die Standardeinstellungen – alles eingeschaltet – sind der richtige Ausgangspunkt für jede Debugging-Sitzung zwischen Host und Kamera. Sobald die Anwendung im Produktiveinsatz ist, werden die Abwägungen spezifisch für ihre Daten und ihren Transport.
12.5.5. Die Statuscodes¶
Wenn ein Transportfehler tatsächlich bis zum Anwendungscode hochpropagiert, kommt er als Statuscode an. Die Protokollbibliothek definiert zehn davon:
SUCCESS– Vorgang abgeschlossen.FAILED– Befehl aus einem nicht näher spezifizierten Grund fehlgeschlagen.INVALID– der Empfänger hat den Befehl oder eines seiner Argumente abgelehnt.TIMEOUT– ein Wiederholungs-Timer ist abgelaufen.BUSY– die Kamera ist beschäftigt (typischerweise ein gesperrter Kanal).CHECKSUM– der CRC des Headers oder der Nutzlast stimmte nicht überein.SEQUENCE– die Sequenznummer war außerhalb der Reihenfolge, über das hinaus, was die Schicht wiederherstellen kann.OVERFLOW– eine Nutzlast hat das ausgehandelte Maximum überschritten.FRAGMENT– eine aus mehreren Fragmenten bestehende Nachricht kam mit fehlenden Teilen an.UNKNOWN– ein defensiver Auffangwert für wirklich unerwartete Situationen.
Host-Code, der channel_read() aufruft, sieht diese als Python-Ausnahmen; kameraseitiger Anwendungscode, der sich für eine eigene Fehlerbehandlung entschieden hat, sieht sie als Rückgabewerte der Backend-Callbacks. Die meisten Kamera-Apps müssen sich die Statuscodes überhaupt nicht ansehen – die Bibliothek übernimmt den erneuten Versuch, und nur wirklich nicht behebbare Fehler (z. B. wenn der Transport selbst weg ist) erreichen die Anwendung.
Mit dem Framing zur Erkennung von Beschädigungen und der Zuverlässigkeitsschicht zur Wiederherstellung danach ist die Arbeit auf Leitungsebene erledigt. Der Anwendungscode sieht geframte, geordnete, intakte Pakete; die Bytes darin können bedeuten, was auch immer der darüberliegende Kanal will.