12.5. Tillförlitlighet – sekvenser, ACK:ar, återsändningar¶
Inramningslagret upptäcker korruption med hjälp av sina CRC:er. Tillförlitlighetslagret förvandlar ”upptäckt korruption” till ”applikationen ser aldrig trasiga data” genom att förhandla om återsändningar varje gång ett paket inte anländer intakt.
12.5.1. Sekvensnummer¶
Varje pakethuvud bär ett sekvensnummer på en byte, separat för varje färdriktning. Sändaren ökar räknaren före sändning; mottagaren kontrollerar att varje mottaget pakets sekvens är den föregående plus ett (modulo 256).
Tre saker kan dyka upp hos mottagaren i stället för ett rent paket i rätt ordning:
Det förväntade sekvensnumret, med en giltig CRC. Paketet levereras vidare till nästa lager.
Det förväntade sekvensnumret, med en felaktig CRC. Mottagaren förkastar paketet och skickar (om ACK:ar har förhandlats fram) en NAK som begär en återsändning.
Ett sekvensnummer som är ett högre än förväntat, med en giltig CRC. Mottagaren vet att det föregående paketet försvann; den skickar en NAK som hänvisar till den missade sekvensen och lagrar undan det nya.
Dubblettfallet (en återsändning som anländer efter att originalet till slut kommit fram) hanteras genom att kontrollera mot den förväntade räknaren: om sekvensen ligger bakom den förväntade är paketet en dubblett, och mottagaren kasserar det efter att ha skickat den ACK som sändaren uppenbarligen inte fick första gången.
12.5.2. ACK och NAK¶
Två flaggbitar i pakethuvudet bär själva tillförlitlighetstrafiken:
ACK_REQsatt på ett utgående paket betyder ”jag vill ha en bekräftelse tillbaka.” Datapaket sätter normalt denna; statuspingningar och enstaka händelser kanske inte gör det.ACKsatt på ett paket betyder ”detta paket är bekräftelsen för sekvensnumret i huvudet.” Det bär ingen egen nyttolast.NAKsatt betyder ”detta paket avvisar ett föregående” – vanligtvis på grund av en felaktig CRC eller ett glapp i sekvensnumren. Huvudet pekar ut för sändaren vilken sekvens som ska återsändas.
Sändaren kör en stopp-och-vänta-slinga: den sänder ett paket som kräver bekräftelse och väntar sedan på den matchande ACK:n (eller NAK:n) innan nästa skickas. Modellen med ett enda paket i transit håller sändarens tillstånd begränsat – några hundra byte på de minsta kamerorna – och passar protokollets roll som en styrkanal mellan två slutpunkter snarare än en genomströmningsoptimerad pipeline. Vid NAK återsänder sändaren samma paket med flaggan RTX satt så att mottagaren vet att det är ett nytt försök.
12.5.3. Tidsstyrning för återsändning¶
Om varken ACK eller NAK anländer inom återsändningstimeouten återsänder sändaren det paket som är i transit på eget initiativ. Timeouten är som standard 500 ms och fördubblas vid varje på varandra följande försök (1 s, 2 s, …). Efter det konfigurerade antalet försök – tre som standard – ger sändaren upp och rapporterar ett transportfel till applikationen.
Att fördubbla timeouten är det vanliga mönstret exponentiell backoff. En kort första timeout fångar upp förlorade paket snabbt; fördubblingen innebär att en värd som är upptagen i några hundra millisekunder inte utlöser en storm av dubbletter som förvärrar belastningen.
12.5.4. Konfigurera tillförlitlighet¶
Båda ändarna kan, efter överenskommelse, stänga av delar av tillförlitlighetslagret när applikationen har råd att förlora data:
protocol.init(ack=False)inaktiverar ACK:ar per paket. Sändaren skickar och glömmer; mottagaren levererar vad som än anländer. Bra för strömmande sensordata där ett föråldrat sampel är acceptabelt.protocol.init(seq=False)stänger av spårning av sekvensnummer, vilket innebär att ACK:ar också stängs av. Användbart endast på helt tillförlitliga transporter.protocol.init(crc=False)stänger av CRC-valideringen men lämnar resten av inramningen intakt. Lönar sig endast när själva transporten är robust nog för att CRC-fel inte ska inträffa.
Standardvärdena – allt på – är den rätta utgångspunkten för varje felsökningssession mellan värd och kamera. När applikationen väl är i produktion blir avvägningarna specifika för dess data och dess transport.
12.5.5. Statuskoderna¶
När ett transportfel väl propagerar upp till applikationskoden anländer det som en statuskod. Protokollbiblioteket definierar tio:
SUCCESS– operationen slutfördes.FAILED– kommandot misslyckades av ospecificerad anledning.INVALID– mottagaren avvisade kommandot eller ett av dess argument.TIMEOUT– en timer för nytt försök löpte ut.BUSY– kameran är upptagen (vanligtvis en låst kanal).CHECKSUM– CRC:n för huvudet eller nyttolasten matchade inte.SEQUENCE– sekvensnumret var i fel ordning utöver vad lagret kan återhämta sig från.OVERFLOW– en nyttolast överskred det förhandlade maximum.FRAGMENT– ett meddelande med flera fragment anlände med saknade delar.UNKNOWN– en defensiv uppsamlingskod för genuint oväntade tillstånd.
Värdkod som anropar channel_read() ser dessa som Python-undantag; applikationskod på kamerasidan som har valt anpassad felhantering ser dem som returvärden från backend-återanropen. De flesta kameraapplikationer behöver inte titta på statuskoderna alls – biblioteket hanterar det nya försöket, och endast genuint oåterställbara fel (t.ex. att själva transporten är borta) når applikationen.
Med inramning på plats för att upptäcka korruption och tillförlitlighet på plats för att återhämta sig från den är arbetet på trådnivå klart. Applikationskoden ser inramade, ordnade och intakta paket; byten inuti dem är fria att betyda vad än kanalen ovanför vill att de ska betyda.