COAP大块数据的块传输机制
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