12.5. Megbízhatóság – sorszámok, ACK-k, újraküldések#

A keretezési réteg a CRC-k segítségével észleli a sérülést. A megbízhatósági réteg az „észlelt sérülést” azzá alakítja, hogy „az alkalmazás soha nem lát hibás adatot”, úgy, hogy újraküldéseket egyeztet minden alkalommal, amikor egy csomag nem érkezik meg sértetlenül.

12.5.1. Sorszámok#

Minden csomag fejléce egy egybájtos sorszámot hordoz, külön mindkét haladási irányhoz. A küldő az átvitel előtt növeli a számlálót; a fogadó ellenőrzi, hogy minden beérkező csomag sorszáma az előzőnél eggyel nagyobb-e (modulo 256).

Három dolog jelenhet meg a fogadónál egy tiszta, sorrendben érkező csomag helyett:

  • A várt sorszám, érvényes CRC-vel. A csomagot a rendszer továbbítja a következő rétegnek.

  • A várt sorszám, hibás CRC-vel. A fogadó eldobja a csomagot, és (ha ACK-k vannak egyeztetve) NAK-ot küld újraküldést kérve.

  • Egy a vártnál eggyel nagyobb sorszám, érvényes CRC-vel. A fogadó tudja, hogy az előző csomag elveszett; NAK-ot küld a kimaradt sorszámra hivatkozva, és eltárolja az újat.

A duplikátum esetét (egy újraküldés érkezik azután, hogy az eredeti végül átért) a várt számlálóval való összevetés kezeli: ha a sorszám a vártnál hátrébb van, a csomag duplikátum, és a fogadó eldobja, miután elküldte azt az ACK-ot, amelyet a küldő nyilvánvalóan nem kapott meg első alkalommal.

12.5.2. ACK és NAK#

A csomag fejlécében két jelzőbit hordozza magát a megbízhatósági forgalmat:

  • Egy kimenő csomagra beállított ACK_REQ azt jelenti: „Visszaigazolást kérek.” Az adatcsomagok ezt általában beállítják; az állapot-pingek és az egyszeri események esetleg nem.

  • Egy csomagra beállított ACK azt jelenti: „ez a csomag a fejlécben szereplő sorszám visszaigazolása.” Saját hasznos adatot nem hordoz.

  • A beállított NAK azt jelenti: „ez a csomag elutasít egy korábbit” – általában hibás CRC vagy sorszám-hézag miatt. A fejléc megmutatja a küldőnek, melyik sorszámot kell újraküldeni.

A küldő stop-and-wait ciklust futtat: elküld egy visszaigazolást igénylő csomagot, majd a következő küldése előtt megvárja a hozzá tartozó ACK-ot (vagy NAK-ot). Az egyetlen-úton-lévő modell korlátok között tartja a küldő állapotát – néhány száz bájt a legkisebb kamerákon –, és illeszkedik a protokoll szerepéhez, amely két végpont közötti vezérlőcsatorna, nem pedig átviteli teljesítményre optimalizált adatfolyam. NAK esetén a küldő ugyanazt a csomagot a RTX jelzővel beállítva küldi újra, hogy a fogadó tudja, ez egy újrapróbálkozás.

12.5.3. Újraküldés időzítése#

Ha sem ACK, sem NAK nem érkezik az újraküldési időkorláton belül, a küldő magától küldi újra az úton lévő csomagot. Az időkorlát alapértelmezett értéke 500 ms, és minden egymást követő újrapróbálkozásnál megduplázódik (1 s, 2 s, …). A beállított számú újrapróbálkozás után – alapértelmezésben három – a küldő feladja, és transzporthibát jelent az alkalmazásnak.

Az időkorlát megduplázása a szabványos exponenciális visszalépés (exponential backoff) minta. A rövid első időkorlát gyorsan elkapja az elveszett csomagokat; a duplázás azt jelenti, hogy egy néhány száz milliszekundumig elfoglalt gazdagép nem indít be egy duplikátumokból álló rohamot, amely tovább növelné a terhelést.

12.5.4. A megbízhatóság konfigurálása#

Mindkét végpont kikapcsolhat a megbízhatósági réteg egyes részeit – megegyezés alapján –, ha az alkalmazás megengedheti magának az adatvesztést:

  • A protocol.init(ack=False) letiltja a csomagonkénti ACK-kat. A küldő elküldi és elfelejti; a fogadó kézbesíti azt, ami megérkezik. Jó olyan érzékelőadatok streameléséhez, ahol egy elavult minta elfogadható.

  • A protocol.init(seq=False) kikapcsolja a sorszámkövetést, ami egyúttal az ACK-k kikapcsolását is jelenti. Csak tökéletesen megbízható transzportokon hasznos.

  • A protocol.init(crc=False) kikapcsolja a CRC-ellenőrzést, de a keretezés többi részét érintetlenül hagyja. Csak akkor érdemes, ha maga a transzport elég robusztus ahhoz, hogy CRC-hibák ne forduljanak elő.

Az alapértelmezések – minden bekapcsolva – a megfelelő kiindulópont bármilyen gazdagép-kamera hibakeresési munkamenethez. Amint az alkalmazás éles üzembe kerül, a kompromisszumok az adataira és a transzportjára nézve specifikussá válnak.

12.5.5. Az állapotkódok#

Amikor egy transzporthiba felbukkan az alkalmazás kódjáig, állapotkódként érkezik. A protokollkönyvtár tízet definiál:

  • SUCCESS – a művelet sikeresen befejeződött.

  • FAILED – a parancs meghatározatlan okból meghiúsult.

  • INVALID – a fogadó elutasította a parancsot vagy annak egyik argumentumát.

  • TIMEOUT – egy újrapróbálkozási időzítő lejárt.

  • BUSY – a kamera foglalt (jellemzően egy zárolt csatorna).

  • CHECKSUM – a fejléc vagy a hasznos adat CRC-je nem egyezett.

  • SEQUENCE – a sorszám olyan mértékben volt sorrenden kívül, amelyből a réteg már nem tud helyreállni.

  • OVERFLOW – egy hasznos adat túllépte az egyeztetett maximumot.

  • FRAGMENT – egy több fragmensből álló üzenet hiányzó darabokkal érkezett.

  • UNKNOWN – egy védekező gyűjtőkód a valóban váratlan helyzetekre.

A channel_read() metódust hívó gazdagép-kód ezeket Python-kivételekként látja; az egyedi hibakezelést választó kamera-oldali alkalmazáskód pedig a backend visszahívásokból visszatérési értékekként kapja meg őket. A legtöbb kameraalkalmazásnak egyáltalán nem kell az állapotkódokat figyelnie – a könyvtár kezeli az újrapróbálkozást, és csak a valóban helyrehozhatatlan hibák (pl. maga a transzport eltűnt) érik el az alkalmazást.

Most, hogy a keretezés a sérülés észlelésére, a megbízhatóság pedig a helyreállításra a helyén van, a vezetékszintű munka kész. Az alkalmazáskód keretezett, rendezett, sértetlen csomagokat lát; a bennük lévő bájtok szabadon jelenthetnek bármit, amit a fölöttük lévő csatorna szán nekik.