12.5. Spolehlivost – sekvence, ACK, opakované přenosy¶
Vrstva rámcování (framing) detekuje poškození pomocí svých CRC. Vrstva spolehlivosti mění „detekované poškození“ na „aplikace nikdy nevidí poškozená data“ tím, že vyjednává opakované přenosy pokaždé, když paket nedorazí neporušený.
12.5.1. Sekvenční čísla¶
Každá hlavička paketu nese jednobajtové sekvenční číslo, oddělené pro každý směr přenosu. Odesílatel zvýší čítač před vysláním; přijímač kontroluje, že sekvence každého přijatého paketu je předchozí plus jedna (modulo 256).
Na přijímači se místo čistého paketu ve správném pořadí mohou objevit tři věci:
Očekávané sekvenční číslo s platnou CRC. Paket je předán další vrstvě.
Očekávané sekvenční číslo s vadnou CRC. Přijímač paket zahodí a (pokud jsou vyjednány ACK) odešle NAK s žádostí o opakovaný přenos.
Sekvenční číslo o jedno vyšší, než se očekává, s platnou CRC. Přijímač ví, že předchozí paket se ztratil; odešle NAK odkazující na zmeškanou sekvenci a nový paket uschová.
Případ duplikátu (opakovaný přenos dorazí poté, co původní paket nakonec prošel) je ošetřen kontrolou vůči očekávanému čítači: pokud je sekvence pozadu za očekávanou, paket je duplikát a přijímač jej zahodí poté, co odešle ACK, který odesílatel zjevně napoprvé nedostal.
12.5.2. ACK a NAK¶
Dva příznakové bity v hlavičce paketu nesou samotný provoz spolehlivosti:
ACK_REQnastavený na odchozím paketu znamená „chci zpět potvrzení.“ Datové pakety jej běžně nastavují; stavové pingy a jednorázové události nemusí.ACKnastavený na paketu znamená „tento paket je potvrzením pro sekvenční číslo v hlavičce.“ Nenese žádný vlastní obsah.NAKnastavený znamená „tento paket odmítá předchozí“ – obvykle kvůli vadné CRC nebo mezeře v sekvenčních číslech. Hlavička odesílateli ukazuje, kterou sekvenci znovu odeslat.
Odesílatel běží ve smyčce stop-and-wait: vyšle jeden paket, který vyžaduje potvrzení, a poté čeká na odpovídající ACK (nebo NAK), než odešle další. Model s jediným paketem na cestě udržuje stav odesílatele ohraničený – několik set bajtů na nejmenších kamerách – a odpovídá roli protokolu jako řídicího kanálu mezi dvěma koncovými body, nikoli potrubí optimalizovaného na propustnost. Při NAK odesílatel znovu odešle stejný paket s nastaveným příznakem RTX, aby přijímač věděl, že jde o opakování.
12.5.3. Časování opakovaného přenosu¶
Pokud do časového limitu opakovaného přenosu nedorazí ani ACK, ani NAK, odesílatel znovu odešle paket na cestě sám. Časový limit má výchozí hodnotu 500 ms a při každém dalším opakování se zdvojnásobuje (1 s, 2 s, …). Po nakonfigurovaném počtu opakování – výchozí jsou tři – to odesílatel vzdá a nahlásí aplikaci chybu transportu.
Zdvojnásobení časového limitu je standardní vzor exponenciálního ústupu (backoff). Krátký první časový limit rychle zachytí ztracené pakety; zdvojnásobování znamená, že host, který je na několik set milisekund zaneprázdněn, nespustí bouři duplikátů, které zátěž ještě znásobí.
12.5.4. Konfigurace spolehlivosti¶
Oba konce mohou po dohodě vypnout části vrstvy spolehlivosti, pokud si aplikace může dovolit ztrátu dat:
protocol.init(ack=False)vypne ACK pro jednotlivé pakety. Odesílatel vystřelí a zapomene; přijímač doručí, cokoli dorazí. Vhodné pro streamování dat ze senzoru, kde je zastaralý vzorek přijatelný.protocol.init(seq=False)vypne sledování sekvenčních čísel, což zároveň znamená i vypnutí ACK. Užitečné pouze na dokonale spolehlivých transportech.protocol.init(crc=False)vypne ověřování CRC, ale ponechá zbytek rámcování beze změny. Vyplatí se pouze tehdy, když je samotný transport dostatečně robustní na to, aby k chybám CRC nedocházelo.
Výchozí nastavení – vše zapnuto – je správný výchozí bod pro jakoukoli ladicí relaci mezi hostem a kamerou. Jakmile je aplikace v produkci, stanou se kompromisy specifickými pro její data a její transport.
12.5.5. Stavové kódy¶
Když se chyba transportu skutečně rozšíří až do kódu aplikace, dorazí jako stavový kód. Knihovna protokolu jich definuje deset:
SUCCESS– operace dokončena.FAILED– příkaz selhal z neurčeného důvodu.INVALID– přijímač odmítl příkaz nebo jeden z jeho argumentů.TIMEOUT– vypršel časovač opakování.BUSY– kamera je zaneprázdněna (typicky uzamčený kanál).CHECKSUM– CRC hlavičky nebo obsahu se neshodovala.SEQUENCE– sekvenční číslo bylo mimo pořadí nad rámec toho, co vrstva dokáže obnovit.OVERFLOW– obsah překročil vyjednané maximum.FRAGMENT– vícefragmentová zpráva dorazila s chybějícími částmi.UNKNOWN– obranný univerzální kód pro skutečně neočekávané podmínky.
Kód hosta volající channel_read() je vidí jako výjimky Pythonu; kód aplikace na straně kamery, který se přihlásil k vlastnímu zpracování chyb, je vidí jako návratové hodnoty z callbacků backendu. Většina aplikací pro kameru se na stavové kódy vůbec nemusí dívat – knihovna zpracuje opakování a aplikace se dotknou pouze skutečně neobnovitelné chyby (např. samotný transport zmizel).
S rámcováním na místě pro detekci poškození a spolehlivostí na místě pro obnovu z něj je práce na úrovni linky hotová. Kód aplikace vidí rámcované, seřazené a neporušené pakety; bajty uvnitř nich mohou znamenat cokoli, co po nich chce vrstva nad kanálem.