Перейти к содержанию

Блочная передача CoAP (Block-Wise Transfer)

Прошивка для обновления по воздуху или длинный JSON не помещаются в одну датаграмму, а фрагментацию IP в сетях датчиков стараются не допускать. Block-wise transfer переносит тело по частям обычными запросами CoAP, по одному блоку на сообщение.

Обновлено Редакция GAW

Блочная передача CoAP (block-wise transfer) — механизм RFC 7959, который переносит большое тело запроса или ответа CoAP серией обычных сообщений, по одному блоку в каждом. Причины не класть всё в одну датаграмму перечислены в разд. 2 стандарта: предел UDP около 64 КиБ, нежелательная фрагментация IP при MTU 1280 байт в IPv6 и крошечные кадры 6LoWPAN, где на полезную нагрузку остаётся 60–80 байт. Две опции делят работу по направлениям: Block1 описывает тело запроса (PUT, POST), Block2 — тело ответа (GET и ответы 2.01, 2.02, 2.04, 2.05).

Устройство опции

Значение опции — беззнаковое целое длиной 0–3 байта с тремя полями (разд. 2.2):

ПолеБитыСмысл
NUMвсё, кроме младших 4 битномер блока, с нуля
M4-й младший бит1 — есть ещё блоки, 0 — последний
SZX3 младших битаразмер блока 2^(SZX + 4): от 16 байт (SZX = 0) до 1024 байт (SZX = 6)

Значение SZX = 7 (2048 байт) зарезервировано: в запросе оно вызывает 4.00 Bad Request. Смещение блока в теле — NUM × 2^(SZX + 4) байт. Опции критические: получатель, который их не понимает, обязан отклонить сообщение. Номера в реестре IANA — 23 для Block2, 27 для Block1 и 28 для Size2 (разд. 6).

Чтение по частям: Block2

Если ответ на GET пришёл с Block2 и M = 1, клиент запрашивает следующие блоки теми же опциями запроса плюс Block2 с нужным NUM и размером; в запросе бит M всегда 0 (разд. 2.4). Желаемый размер клиент может задать уже в первом запросе — сервер использует его или меньший, и дальше размер не меняется до последнего, неполного блока. Для ресурса, который может измениться между блоками, сервер должен добавлять ETag, а клиент — собирать тело только из блоков с одинаковым ETag. Запрос с Size2 = 0 просит сервер сообщить полный размер тела (разд. 4).

Запись по частям: Block1

При PUT или POST клиент сам режет тело и ставит Block1 в каждом запросе. В ответе на первый блок сервер через Block1 сообщает предпочтительный размер, и клиент переходит на него или меньший (разд. 2.5). Если сервер пишет ресурс атомарно, он создаёт его только по последнему блоку (M = 0), а на промежуточные отвечает 2.31 Continue. Нет нужных блоков — 4.08 Request Entity Incomplete; частичное тело сервер вправе забыть через EXCHANGE_LIFETIME, поэтому блоки стоит слать без пауз и строго по порядку с нулевого. Ответ 4.13 Request Entity Too Large с опцией Size1 — подсказка: тело не влезает, попробуй Block1 или меньший SZX (разд. 2.9.3).

Где встречается

Типичный случай — обновление прошивки по воздуху через CoAP: образ в сотни килобайт уходит блоками по 1024 байта (по Ethernet) или 64 байта (в 6LoWPAN), и каждый блок подтверждается как обычное сообщение CON, так что потерянный фрагмент повторяется средствами CoAP, а не всей передачей. RFC 7959 также описывает сочетание Block2 с опцией Observe — уведомление приходит первым блоком, остальные клиент дочитывает сам. Библиотека CoAP в Zephyr (CONFIG_COAP) заявляет поддержку RFC 7959 с оговоркой, что поддержаны не все части стандарта. В отличие от обнаружения MTU пути, блочная передача не подбирает размер датаграммы на уровне IP, а заранее держит каждое сообщение маленьким — это и есть рекомендация RFC 7252 для ограниченных сетей. О разборе и сборке таких сообщений в прошивке — в статье о реализации протоколов.

Частые вопросы

Чем Block1 отличается от Block2?

Цифра указывает на тело, к которому относится опция: 1 — тело запроса, 2 — тело ответа. Block1 нужен, когда клиент загружает на сервер большой PUT или POST, например кусок прошивки. Block2 — когда клиент читает большой ответ по GET. Обе опции могут стоять и в запросе, и в ответе: в сообщении со «своим» телом они описывают блок, в обратном направлении — управляют размером (RFC 7959, разд. 2.1).

Какой размер блока выбрать?

Любую степень двойки от 16 до 1024 байт — поле SZX кодирует размер как 2^(SZX + 4), SZX от 0 до 6. Для 6LoWPAN RFC 7959 называет полезную нагрузку кадра 60–80 байт, поэтому там уместны 64 байта; по Ethernet и Wi-Fi обычно берут 1024. Клиент предлагает размер в первом запросе, сервер вправе уменьшить его, и дальше все блоки, кроме последнего, идут одного размера.

Что означают коды 2.31 и 4.08?

Оба введены RFC 7959 для загрузки через Block1. 2.31 Continue сервер отвечает на каждый промежуточный блок: принял, присылай дальше, итог пока неизвестен. 4.08 Request Entity Incomplete — у сервера нет нужных блоков: клиент прислал их не все, не по порядку или слишком давно, и сервер уже выбросил частичное тело. Клиенту остаётся начать передачу заново с нулевого блока.

Источники

  1. C. Bormann, Z. Shelby (Ed.). Block-Wise Transfers in the Constrained Application Protocol (CoAP). RFC 7959, August 2016 — разд. 2: причины ограничивать датаграммы — около 64 КиБ у UDP, MTU 1280 у IPv6, 60–80 байт для 6LoWPAN; Block1 относится к телу запроса, Block2 — к телу ответа; Content-Format и ETag относятся ко всему телу, а не к блоку; размеры блоков — степени двойки от 2^4 (16) до 2^10 (1024) байт, все блоки, кроме последнего, одного размера; разд. 2.1, табл. 1: Block2 — опция 23, Block1 — опция 27, обе критические (Critical) и Unsafe, формат uint 0–3 байта, Block1 полезен с POST и PUT, Block2 — с GET, POST, PUT и ответами 2.01, 2.02, 2.04, 2.05; описательное (descriptive) и управляющее (control) использование; не более одного вхождения каждой опции в сообщении; разд. 2.2: поля NUM, M, SZX, размер блока 2^(SZX + 4), SZX от 0 до 6, значение 7 (2048) зарезервировано и в запросе вызывает 4.00 Bad Request, отсутствие опции означает единственный блок; разд. 2.4: клиент может задать желаемый размер в первом запросе с Block2, сервер использует его или меньший, в запросах M = 0; для меняющихся ресурсов Block2 сочетают с ETag; разд. 2.5: сервер в ответе через Block1 сообщает предпочтительный размер, клиент переходит на него или меньший; при атомарной записи ресурс создаётся по последнему блоку (M = 0), промежуточные ответы 2.31 Continue, недостающие блоки — 4.08 Request Entity Incomplete, сервер вправе забыть частичное тело через EXCHANGE_LIFETIME; разд. 2.9: новые коды 2.31 Continue и 4.08 Request Entity Incomplete, 4.13 Request Entity Too Large с Size1 — подсказка попробовать Block1 или меньший SZX; разд. 4: Size1 — размер тела запроса, Size2 — размер тела ответа, в запросе Size2 = 0 означает «сообщи размер»; разд. 6, табл. 3 и 4: номера опций 23 Block2, 27 Block1, 28 Size2, коды 2.31 и 4.08 в реестрах IANA
  2. Zephyr Project. Zephyr Project Documentation, latest: Networking APIs — CoAP — библиотека CoAP Zephyr (CONFIG_COAP) заявляет поддержку RFC 7959 наряду с RFC 7252, 6690, 7641, 8613, с оговоркой, что поддержаны не все части этих RFC
Страница помогла?

Нашли ошибку? ·