/* 我正在从 CoAP 服务器 向 CoAP 客户端 发送超过 1024 大小的响应。但是,我无法在 CoAP 客户端中接收完整的数据。我只能接收 1024 大小的数据。
用于在服务器中发送较大数据的API: coap_add_data_large_response()
客户端用于接收较大数据的API: coap_get_data_large()
但是,在wireshark中,完整的数据以2个块或pdu的形式发送。例如,如果数据大小为1224,则发送的第一组数据为1024大小,发送的第二组数据为200大小。但我无法收到完整的数据。
请您指导一下,如何在CoAP客户端中接收完整的数据(超过1024)。
如何使用此 API coap_block_build_body() 将多个块或 pdu 的数据收集为单个大数据(超过 1024)。 */
/***********CoAP Server Code***************/
#include <coap3/coap.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#define GET_CMD "get_details"
int resolve_address(const char *host, const char *service, coap_address_t *dst)
{
struct addrinfo *res, *ainfo;
struct addrinfo hints;
int error, len = -1;
memset(&hints, 0, sizeof(hints));
memset(dst, 0, sizeof(*dst));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = AF_UNSPEC;
error = getaddrinfo(host, service, &hints, &res);
if (error != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
return error;
}
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
switch (ainfo->ai_family) {
case AF_INET6:
case AF_INET:
len = dst->size = ainfo->ai_addrlen;
memcpy(&dst->addr.sin6, ainfo->ai_addr, dst->size);
default:
;
}
}
freeaddrinfo(res);
return len;
}
static void resource_handler(struct coap_resource_t *resource,
struct coap_session_t *session, const struct coap_pdu_t *request,
const struct coap_string_t *query, struct coap_pdu_t *response) {
uint8_t *payloadBuffer;
size_t payload_len;
size_t offset = 0;
size_t total = 0;
(void) resource;
uint8_t res[2048] =
"[{\"id\":\"0001\",\"type\":\"donut\",\"name\":\"Cake\",\"ppu\":0.55,\"batters\":{\"batter\":[{\"id\":\"1001\",\"type\":\"Regular\"},{\"id\":\"1002\",\"type\":\"Chocolate\"},{\"id\":\"1003\",\"type\":\"Blueberry\"},{\"id\":\"1004\",\"type\":\"Devil's Food\"}]},\"batters\":{\"batter\":[{\"id\":\"1001\",\"type\":\"Regular\"},{\"id\":\"1002\",\"type\":\"Chocolate\"},{\"id\":\"1003\",\"type\":\"Blueberry\"},{\"id\":\"1004\",\"type\":\"Devil's Food\"}]},\"batters\":{\"batter\":[{\"id\":\"1001\",\"type\":\"Regular\"},{\"id\":\"1002\",\"type\":\"Chocolate\"},{\"id\":\"1003\",\"type\":\"Blueberry\"},{\"id\":\"1004\",\"type\":\"Devil's Food\"}]},\"batters\":{\"batter\":[{\"id\":\"1001\",\"type\":\"Regular\"},{\"id\":\"1002\",\"type\":\"Chocolate\"},{\"id\":\"1003\",\"type\":\"Blueberry\"},{\"id\":\"1004\",\"type\":\"Devil's Food\"}]},\"batters\":{\"batter\":[{\"id\":\"1001\",\"type\":\"Regular\"},{\"id\":\"1002\",\"type\":\"Chocolate\"},{\"id\":\"1003\",\"type\":\"Blueberry\"},{\"id\":\"1004\",\"type\":\"Devil's Food\"}]},\"topping\":[{\"id\":\"5001\",\"type\":\"None\"},{\"id\":\"5002\",\"type\":\"Glazed\"},{\"id\":\"5005\",\"type\":\"Sugar\"},{\"id\":\"5007\",\"type\":\"Powdered Sugar\"},{\"id\":\"5006\",\"type\":\"Chocolate with Sprinkles\"},{\"id\":\"5003\",\"type\":\"Chocolate\"},{\"id\":\"5004\",\"type\":\"Maple\"}]},{\"id\":\"0002\",\"type\":\"donut\",\"name\":\"Raised\",\"ppu\":0.55,\"batters\":{\"batter\":[{\"id\":\"1001\",\"type\":\"Regular\"}]},\"topping\":[{\"id\":\"5001\",\"type\":\"None\"},{\"id\":\"5002\",\"type\":\"Glazed\"},{\"id\":\"5005\",\"type\":\"Sugar\"},{\"id\":\"5003\",\"type\":\"Chocolate\"},{\"id\":\"5004\",\"type\":\"Maple\"}]},{\"id\":\"0003\",\"type\":\"donut\",\"name\":\"Old Fashioned\",\"ppu\":0.55,\"batters\":{\"batter\":[{\"id\":\"1001\",\"type\":\"Regular\"},{\"id\":\"1002\",\"type\":\"Chocolate\"}]},\"topping\":[{\"id\":\"5001\",\"type\":\"None\"},{\"id\":\"5002\",\"type\":\"Glazed\"},{\"id\":\"5003\",\"type\":\"Chocolate\"},{\"id\":\"5004\",\"type\":\"Maple\"}]}]";
/* API to receive small data upto 1024 bytes*/
coap_get_data(request, &payload_len, (const uint8_t**) &payloadBuffer);
// /* API to receive large data more than 1024 bytes*/
// coap_get_data_large(request, &payload_len, (const uint8_t **)&payloadBuffer, &offset, &total);
// printf("getHwInfoHandler Query from client: \n%s\n\n", payloadBuffer);
// printf("payload_len %ld\n", payload_len);
// coap_add_data_large_request(session, request, strlen(res), (const uint8_t *)res, NULL, NULL);
const uint8_t *cmd = coap_resource_get_uri_path(resource)->s;
printf("Request received from service tool: %s\n\n", cmd);
#if 1
if (cmd != NULL) {
if ((strcmp(cmd, GET_CMD)) == 0) {
memset(&payloadBuffer, 0, payload_len);
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
printf("json sent to client: \n%s\n\n", res);
printf("strlen(res) %ld\n", strlen(res));
// coap_add_data(response, strlen(res), (const uint8_t *)res);
// coap_add_data_large_request(session, request, strlen(res), (const uint8_t *)res, NULL, NULL);
// coap_add_data_large_request(session, request2, 6, "buffer", NULL, NULL);
// coap_add_data_large_response(resource,session,request,response,query,0,-1,0,strlen(res), (const uint8_t *)res,NULL,NULL);
int retval = coap_add_data_large_response(resource, session,
request, response, query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
strlen(res), (const uint8_t*) res, NULL, NULL);
// int retval = coap_add_data_large_response(resource, session, request, response, query, COAP_MEDIATYPE_APPLICATION_COAP_GROUP_JSON, 1, 0, strlen(res), (const uint8_t *)res,NULL,NULL);
printf("coap_add_data_large_response():retval: %d\n", retval);
}
}
#endif
}
int main() {
coap_context_t *ctx;
coap_endpoint_t *endpoint;
coap_resource_t *resource;
coap_resource_t *resource2;
coap_resource_t *resource3;
coap_address_t listen_addr;
coap_str_const_t *ruri = coap_make_str_const("get_details");
coap_startup();
resolve_address("127.0.0.1", "5683", &listen_addr); //127.0.0.1 //192.168.1.6
ctx = coap_new_context(NULL);
coap_new_endpoint(ctx, &listen_addr, COAP_PROTO_UDP);
resource = coap_resource_init(ruri, 0);
coap_context_set_block_mode(ctx,
COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
// coap_context_set_block_mode(ctx, COAP_BLOCK_USE_LIBCOAP);
coap_register_handler(resource, COAP_REQUEST_PUT, resource_handler);
coap_add_resource(ctx, resource);
while (1) {
int result = coap_io_process(ctx, COAP_IO_WAIT);
}
coap_free_context(ctx);
coap_cleanup();
return EXIT_`SUCCESS;
}
/***********CoAP Client Code***************/
#include <coap3/coap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
static int have_response = 0;
char *buffer; // = "testing 123";
int resolve_address(const char *host, const char *service, coap_address_t *dst) {
struct addrinfo *res, *ainfo;
struct addrinfo hints;
int error, len = -1;
memset(&hints, 0, sizeof(hints));
memset(dst, 0, sizeof(*dst));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = AF_UNSPEC;
error = getaddrinfo(host, service, &hints, &res);
if (error != 0) {
printf("getaddrinfo: %s\n", gai_strerror(error));
return error;
}
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
switch (ainfo->ai_family) {
case AF_INET6:
case AF_INET:
len = dst->size = ainfo->ai_addrlen;
memcpy(&dst->addr.sin6, ainfo->ai_addr, dst->size);
default:
;
}
}
freeaddrinfo(res);
return len;
}
coap_response_t response_handler(struct coap_session_t *session,
const struct coap_pdu_t *request, const struct coap_pdu_t *response,
const coap_mid_t mid) {
size_t payload_len;
size_t coap_ret;
uint8_t *payloadBuffer = NULL;
size_t offset = 0;
size_t total = 0;
size_t size;
// Get the payload (data) from the request
// coap_ret = coap_get_data(response, &payload_len, &payloadBuffer);
#if 1
/* API to receive large data more than 1024 bytes*/
coap_get_data_large(response, &payload_len, (const uint8_t**) &payloadBuffer,
&offset, &total);
printf("Response from server: \n%s\n\n", payloadBuffer);
printf("payload_len: %ld\n", payload_len);
printf("offset: %ld\n", offset);
printf("total: %ld\n", total);
#endif
memset(payloadBuffer, '\0', payload_len);
}
int main() {
printf("CoAP_client\n");
coap_context_t *ctx = NULL;
coap_session_t *session = NULL;
coap_pdu_t *request = NULL;
coap_address_t server_address;
coap_address_t client_address;
coap_optlist_t *optlist = NULL;
coap_pdu_t *response = NULL;
unsigned char *response_data = NULL;
size_t response_length = 0;
long file_size;
coap_startup();
ctx = coap_new_context(NULL);
if (!ctx) {
return 0;
}
coap_context_set_block_mode(ctx,
COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
// coap_context_set_block_mode(ctx, COAP_BLOCK_USE_LIBCOAP);
resolve_address("127.0.0.1", "5683", &server_address); //127.0.0.1
session = coap_new_client_session(ctx, NULL, &server_address, COAP_PROTO_UDP);
if (!session) {
printf("Failed to create client session\n");
coap_free_context(ctx);
return EXIT_FAILURE;
}
coap_register_response_handler(ctx, response_handler);
request = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_PUT,
coap_new_message_id(session), coap_session_max_pdu_size(session));
coap_add_option(request, COAP_OPTION_URI_PATH, strlen("get_details"),
(const uint8_t*) "get_details");
printf("******* get_details *******\n\n\n");
if (coap_send(session, request) == -1) {
printf("send failed\n");
coap_free_context(ctx);
return EXIT_FAILURE;
} else {
printf("send success\n");
}
coap_io_process(ctx, COAP_IO_WAIT);
coap_session_release(session);
coap_free_context(ctx);
coap_cleanup();
return EXIT_SUCCESS;
}
CoAP 将更大的有效负载拆分为单个请求/响应对。为此,RFC7959 扩展了 RFC 7252 中的基本规范。通常称为“块式”传输。因此,响应包含 CoAP 选项,在本例中为 BLOCK-2 选项,它指示按块传输。然后,客户端被认为请求下一个块,直到服务器在该 BLOCK-2 选项中报告传输已完成。
这可能取决于您使用的客户端库,但通常使用“blockwise”搜索会有所帮助。