Побайтовый layout frozen header, network byte order, bounded payload и строгий порядок validation.
ByteBox/1 header всегда занимает ровно 20 bytes. Его layout frozen как struct.Struct("!4sBBHIII"): четыре raw magic bytes, два one-byte fields, один big-endian uint16 и три big-endian uint32. Символ ! одновременно задаёт network byte order и отсутствие native padding в нормативном Python notation.
Payload начинается только с offset 20 и имеет длину из header. Он binary-safe: NUL внутри content допустим, поэтому strlen, %s и поиск terminator неприменимы. Максимальная payload length — 65536.
| Offset | Size | Field | Contract |
|---|---|---|---|
| 0 | 4 | magic | ASCII BTBX |
| 4 | 1 | version | 1 |
| 5 | 1 | opcode | LIST/GET/response/ERROR code |
| 6 | 2 | status | uint16, big-endian |
| 8 | 4 | request_id | uint32, big-endian; request nonzero |
| 12 | 4 | payload_len | uint32, big-endian; 0..65536 |
| 16 | 4 | payload_crc32 | uint32, big-endian CRC payload |
Native compiler может вставить padding, потребовать alignment и хранить integers в host byte order. Даже pragma pack решает только padding, но не byte order и не безопасный unaligned access. Надёжный decoder читает raw[20], проверяет наличие всех bytes, затем извлекает fields по offsets. Fixed-width values копируются через memcpy в выровненные uint16_t/uint32_t и переводятся ntohs/ntohl. Encoder делает обратное с htons/htonl.
Порядок нужен для safety и синхронизации stream parser. Oversized declaration получает ERROR/FRAME_TOO_LARGE и close без body read. CRC mismatch получает ERROR/BAD_CHECKSUM и close после bounded read.
Перед запуском посчитайте frame size для empty LIST: 20 bytes. Для GET hello.txt payload содержит big-endian name_len 9 и девять ASCII bytes, поэтому request frame содержит 20-byte header плюс 11-byte payload. Это размер ByteBox frame; TCP может доставить его любым числом recv chunks.
Предскажите также outcome для корректного имени missing.bin: server отвечает ровно одним 20-byte ERROR frame, opcode 0xff, status NOT_FOUND=2, echoed request_id, length/CRC zero, без body.
Создайте функции decode_header(raw[20], fields), encode_header(fields, raw[20]), recv_exact и send_all. Unit tests должны использовать literal byte vectors, а не encode и decode одной и той же реализацией: иначе симметричная ошибка byte order останется зелёной.
После payload_len check выделяйте не больше 65536 bytes. Для zero length не требуйте non-null body. Сравнивайте вычисленный CRC как uint32_t и кодируйте его на wire через htonl. CRC check value для ASCII 123456789 равен 0xcbf43926, empty — 0.
Сверяйте каждую цифру с docs/curriculum/computer-networks/capstone-bytebox.md и docs/curriculum/computer-networks/harness/bytebox_protocol.py. Любое wire изменение требует ByteBox/2, а не тихой правки harness.
Введите числа или выберите пресет