12.5. ความน่าเชื่อถือ -- ลำดับ, ACK และการส่งซ้ำ

ชั้นการจัดกรอบตรวจจับความเสียหายด้วย CRC ชั้นความน่าเชื่อถือเปลี่ยน "การตรวจพบความเสียหาย" ให้กลายเป็น "แอปพลิเคชันไม่เห็นข้อมูลที่เสียหายเลย" โดยการต่อรองส่งข้อมูลซ้ำเมื่อใดก็ตามที่แพ็กเก็ตไม่มาถึงในสภาพสมบูรณ์

12.5.1. หมายเลขลำดับ

แต่ละส่วนหัวแพ็กเก็ตมีหมายเลขลำดับขนาดหนึ่งไบต์ แยกกันสำหรับแต่ละทิศทางการรับส่ง ผู้ส่งเพิ่มค่าตัวนับก่อนส่ง ผู้รับตรวจสอบว่าลำดับของแต่ละแพ็กเก็ตที่ได้รับคือลำดับก่อนหน้าบวกหนึ่ง (ตามแบบโมดูโล 256)

ผู้รับอาจพบสามสถานการณ์แทนที่จะเป็นแพ็กเก็ตที่มาในลำดับถูกต้อง:

  • หมายเลขลำดับที่คาดไว้ พร้อม CRC ที่ถูกต้อง แพ็กเก็ตถูกส่งต่อไปยังชั้นถัดไป

  • หมายเลขลำดับที่คาดไว้ พร้อม CRC ที่ผิดพลาด ผู้รับทิ้งแพ็กเก็ตและ (หากมีการต่อรอง ACK) ส่ง NAK ขอให้ส่งซ้ำ

  • หมายเลขลำดับที่สูงกว่าที่คาดไว้หนึ่งหมายเลข พร้อม CRC ที่ถูกต้อง ผู้รับรู้ว่าแพ็กเก็ตก่อนหน้าหายไป จึงส่ง NAK อ้างอิงลำดับที่ขาดหายและเก็บอันใหม่ไว้ก่อน

กรณีซ้ำซ้อน (การส่งซ้ำที่มาถึงหลังจากต้นฉบับผ่านมาได้แล้ว) ได้รับการจัดการโดยการตรวจสอบเทียบกับตัวนับที่คาดไว้: หากลำดับนั้น ล้าหลัง ลำดับที่คาดไว้ แพ็กเก็ตนั้นคือสำเนาซ้ำซ้อนและผู้รับจะทิ้งมันทิ้งหลังจากส่ง ACK ที่ผู้ส่งเห็นชัดว่าไม่ได้รับในครั้งแรก

12.5.2. ACK และ NAK

บิตแฟล็กสองบิตในส่วนหัวแพ็กเก็ตรองรับการรับส่งข้อมูลด้านความน่าเชื่อถือ:

  • ACK_REQ ที่ตั้งไว้บนแพ็กเก็ตขาออกหมายความว่า "ฉันต้องการการตอบรับกลับมา" แพ็กเก็ตข้อมูลปกติจะตั้งค่านี้ ส่วนการ ping สถานะและเหตุการณ์ครั้งเดียวอาจไม่ตั้ง

  • ACK ที่ตั้งไว้บนแพ็กเก็ตหมายความว่า "แพ็กเก็ตนี้คือการตอบรับสำหรับหมายเลขลำดับในส่วนหัว" โดยไม่มีเพย์โหลดของตัวเอง

  • NAK ที่ตั้งไว้หมายความว่า "แพ็กเก็ตนี้ปฏิเสธแพ็กเก็ตก่อนหน้า" -- มักเกิดจาก CRC ที่ผิดพลาดหรือช่องว่างในหมายเลขลำดับ ส่วนหัวชี้ให้ผู้ส่งรู้ว่าต้องส่งลำดับใดซ้ำ

ผู้ส่งทำงานแบบวนซ้ำแบบหยุดและรอ: ส่งแพ็กเก็ตหนึ่งชิ้นที่ต้องการการตอบรับ แล้วรอ ACK (หรือ NAK) ที่ตรงกันก่อนส่งอันถัดไป โมเดลการส่งครั้งละหนึ่งชิ้นทำให้สถานะของผู้ส่งมีขอบเขตจำกัด -- สักไม่กี่ร้อยไบต์บนกล้องที่เล็กที่สุด -- และเหมาะกับบทบาทของโปรโตคอลในฐานะช่องควบคุมระหว่างสองจุดสิ้นสุดมากกว่าท่อที่ปรับแต่งเพื่อปริมาณงานที่ผ่านได้ เมื่อได้รับ NAK ผู้ส่งจะส่งแพ็กเก็ตเดิมซ้ำพร้อมตั้งค่าแฟล็ก RTX เพื่อให้ผู้รับรู้ว่าเป็นการลองใหม่

12.5.3. ระยะเวลาการส่งซ้ำ

หากไม่มี ACK หรือ NAK มาถึงภายใน ระยะเวลาหมดเวลาการส่งซ้ำ ผู้ส่งจะส่งแพ็กเก็ตที่กำลังบินอยู่ซ้ำโดยอัตโนมัติ ค่าเริ่มต้นของระยะหมดเวลาคือ 500 ms และจะเพิ่มเป็นสองเท่าในแต่ละการลองซ้ำ (1 วินาที, 2 วินาที, ...) หลังจากจำนวนการลองซ้ำที่กำหนดไว้ -- ค่าเริ่มต้นสามครั้ง -- ผู้ส่งจะยอมแพ้และรายงานข้อผิดพลาดการขนส่งไปยังแอปพลิเคชัน

การเพิ่มระยะหมดเวลาเป็นสองเท่าคือรูปแบบ exponential backoff มาตรฐาน ระยะหมดเวลาครั้งแรกที่สั้นช่วยตรวจจับแพ็กเก็ตที่หายไปได้อย่างรวดเร็ว การเพิ่มสองเท่าหมายความว่าโฮสต์ที่ยุ่งอยู่สักสองสามร้อยมิลลิวินาทีจะไม่กระตุ้นให้เกิดการส่งซ้ำจำนวนมากที่ยิ่งเพิ่มภาระ

12.5.4. การกำหนดค่าความน่าเชื่อถือ

ทั้งสองฝั่งสามารถปิดส่วนต่าง ๆ ของชั้นความน่าเชื่อถือได้โดยข้อตกลง เมื่อแอปพลิเคชันสามารถรับการสูญเสียข้อมูลได้:

  • protocol.init(ack=False) ปิดใช้งาน ACK ต่อแพ็กเก็ต ผู้ส่งส่งและลืม ผู้รับส่งมอบสิ่งที่มาถึง เหมาะสำหรับการสตรีมข้อมูลเซนเซอร์ที่ตัวอย่างเก่าเป็นที่ยอมรับได้

  • protocol.init(seq=False) ปิดการติดตามหมายเลขลำดับ ซึ่งหมายความว่าปิด ACK ด้วย มีประโยชน์เฉพาะบนการขนส่งที่เชื่อถือได้อย่างสมบูรณ์

  • protocol.init(crc=False) ปิดการตรวจสอบ CRC แต่เหลือส่วนที่เหลือของการจัดกรอบไว้ คุ้มค่าที่จะทำเฉพาะเมื่อการขนส่งนั้นแข็งแกร่งพอที่ข้อผิดพลาด CRC ไม่เกิดขึ้น

ค่าเริ่มต้น -- ทุกอย่างเปิดใช้งาน -- คือจุดเริ่มต้นที่ถูกต้องสำหรับทุกเซสชันการดีบักระหว่างโฮสต์กับกล้อง เมื่อแอปพลิเคชันอยู่ในโหมดใช้งานจริง การแลกเปลี่ยนจะขึ้นอยู่กับข้อมูลและการขนส่งของแอปพลิเคชันนั้น ๆ โดยเฉพาะ

12.5.5. รหัสสถานะ

เมื่อข้อผิดพลาดการขนส่งส่งต่อถึงโค้ดแอปพลิเคชัน มันมาในรูปแบบรหัสสถานะ ไลบรารีโปรโตคอลกำหนดไว้สิบรหัส:

  • SUCCESS -- การดำเนินการเสร็จสมบูรณ์

  • FAILED -- คำสั่งล้มเหลวด้วยเหตุผลที่ไม่ระบุ

  • INVALID -- ผู้รับปฏิเสธคำสั่งหรือหนึ่งในอาร์กิวเมนต์

  • TIMEOUT -- ตัวจับเวลาการลองซ้ำหมดเวลา

  • BUSY -- กล้องกำลังยุ่ง (มักเป็นช่องที่ถูกล็อก)

  • CHECKSUM -- CRC ของส่วนหัวหรือเพย์โหลดไม่ตรงกัน

  • SEQUENCE -- หมายเลขลำดับไม่เป็นไปตามลำดับเกินกว่าที่ชั้นนั้นจะกู้คืนได้

  • OVERFLOW -- เพย์โหลดเกินขนาดสูงสุดที่ต่อรองไว้

  • FRAGMENT -- ข้อความหลายส่วนมาถึงโดยขาดชิ้นส่วน

  • UNKNOWN -- การตรวจจับแบบครอบคลุมสำหรับสภาวะที่ไม่คาดคิดอย่างแท้จริง

โค้ดฝั่งโฮสต์ที่เรียก channel_read() จะเห็นสิ่งเหล่านี้ในรูปแบบ exception ของ Python โค้ดแอปพลิเคชันฝั่งกล้องที่เลือกใช้การจัดการข้อผิดพลาดแบบกำหนดเองจะเห็นเป็นค่าที่คืนมาจากคอลแบ็กแบ็กเอนด์ แอปกล้องส่วนใหญ่ไม่จำเป็นต้องดูรหัสสถานะเลย -- ไลบรารีจัดการการลองซ้ำ และเฉพาะความล้มเหลวที่กู้คืนไม่ได้จริง ๆ (เช่น การขนส่งหายไปเอง) เท่านั้นที่จะถึงแอปพลิเคชัน

เมื่อการจัดกรอบพร้อมสำหรับการตรวจจับความเสียหายและความน่าเชื่อถือพร้อมสำหรับการกู้คืน งานระดับสายก็เสร็จสิ้น โค้ดแอปพลิเคชันเห็นแพ็กเก็ตที่จัดกรอบแล้ว เรียงลำดับแล้ว สมบูรณ์แล้ว ไบต์ภายในนั้นอิสระที่จะมีความหมายอะไรก็ได้ตามที่ช่องด้านบนต้องการ