COAP的Block1 Block2

CoAP是一个基于UDP的RESTful传输协议,基本的CoAP消息大小受UDP特性影响最好不要超过MTU size,libcoap库中限制在1024字节。

虽然UDP支持通过IP分片传输更大的有效载荷,且仅限于64KiB,更重要的是,并没有真正很好地约束应用和网络。

COAP则引入的块特性。


以libcoap库举例

参考例程 example/coap-client.c,以下是与块相关的代码:

/**
 * Structure of Block options.
 */
typedef struct {
  unsigned int num;       /**< block number */
  unsigned int m:1;       /**< 1 if more blocks follow, 0 otherwise */
  unsigned int szx:3;     /**< block size */
} coap_block_t;

coap_block_t block = { .num = 0, .m = 0, .szx = 6 };

static int
cmdline_blocksize(char *arg) {
  uint16_t size;

  again:
  size = 0;
  while(*arg && *arg != ',')
    size = size * 10 + (*arg++ - '0');

  if (*arg == ',') {
    arg++;
    block.num = size;
    if (size != 0) {
      /* Random access selection - only handle single response */
      single_block_requested = 1;
    }
    goto again;
  }

  if (size)
    block.szx = (coap_fls(size >> 4) - 1) & 0x07;

  flags |= FLAGS_BLOCK;
  return 1;
}

/* Called after processing the options from the commandline to set
 * Block1 or Block2 depending on method. */
static void
set_blocksize(void) {
  static unsigned char buf[4];        /* hack: temporarily take encoded bytes */
  uint16_t opt;
  unsigned int opt_length;

  if (method != COAP_REQUEST_DELETE) {
    if (method == COAP_REQUEST_GET || method == COAP_REQUEST_FETCH) {
      opt = COAP_OPTION_BLOCK2;
    }
    else {
      opt = COAP_OPTION_BLOCK1;
    }

    block.m = (opt == COAP_OPTION_BLOCK1) &&
      ((1ull << (block.szx + 4)) < payload.length);

    opt_length = coap_encode_var_safe(buf, sizeof(buf),
          (block.num << 4 | block.m << 3 | block.szx));

    coap_insert_optlist(&optlist, coap_new_optlist(opt, opt_length, buf));
  }
}

// 不可缺少
uint16_t cache_ignore_options[] = { COAP_OPTION_BLOCK1,
                                    COAP_OPTION_BLOCK2,
                    /* See https://tools.ietf.org/html/rfc7959#section-2.10 */
                                    COAP_OPTION_MAXAGE,
                    /* See https://tools.ietf.org/html/rfc7959#section-2.10 */
                                    COAP_OPTION_IF_NONE_MATCH };

/* 会影响非开始块的接收 */
coap_context_set_block_mode(ctx, COAP_BLOCK_USE_LIBCOAP);
/* Define the options to ignore when setting up cache-keys */
/* 会影响coap_cache_get_by_pdu在非开始块中正确取值 */
coap_cache_ignore_options(__ctx, cache_ignore_options,
            sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0]));

使用此coap-client例程模拟传输一个大文件

# put文件upload_file文件到coap://127.0.0.1/example_data地址,文件大小超过1024字节以上。
# -b 1024代表按1024字节大小分块传输,-b 取值范围是 16 - 1024。
# 如果upload_file大小为588600,它会被分成575个块。
$ coap-client -v 7 -m put coap://127.0.0.1/example_data -f upload_file -b 1024
# -b 10,1024 的含义为只发送第10号单块数据。
$ coap-client -v 7 -m put coap://127.0.0.1/example_data -f upload_file -b 10,1024