coap的首部结构
消息头(HEAD)
第一行是消息头,必须有,固定4个byte。
Ver : 2bit, 版本信息,当前是必须写0x01。
T: 2bit, 消息类型,包括 CON, NON. ACK, RST这4种。
TKL: 4bit,token长度, 当前支持0~8B长度,其他长度保留将来扩展用。
Code:8bit,分成前3bit(07)和后5bit(031),前3bit代表类型。 0代表空消息或者请求码, 2开头代表响应码,取值如下:
1 0.00 Indicates an Empty message
2 0.01-0.31 Indicates a request.
3 1.00-1.31 Reserved
4 2.00-5.31 Indicates a response.
5 6.00-7.31 Reserved
Message ID:16bit, 代表消息MID,每个消息都有一个ID ,重发的消息MID不变
token(可选)
用于将响应与请求匹配。 token值为0到8字节的序列。 ( 每条消息必须带有一个标记, 即使它的长度为零)。 每个请求都带有一个客户端生成的token, 服务器在任何结果响应中都必须对其进行回应。token类似消息ID,用以标记消息的唯一性。token还是消息安全性的一个设置,使用全8字节的随机数,使伪造的报文无法获得验证通过。
option(可选,0个或者多个)
请求消息 与回应消息都可以0~多个options。 主要用于描述请求或者响应对应的各个属性,类似参数或者特征描述,比如是否用到代理服务器,目的主机的端口等。
payload(可选)
实际携带数据内容, 若有, 前面加payload标识符“0xFF”,如果没有payload标识符,那么就代表这是一个0长度的payload。如果存在payload标识符但其后跟随的是0长度的payload,那么必须当作消息格式错误处理。
COAP的请求码(requests)和响应码(responses)
【0.01】GET方法——用于获得某资源
【0.02】POST方法——用于创建某资源
【0.03】PUT方法——用于更新某资源
【0.04】DELETE方法——用于删除某资源
函数使用
1.保存将要发送数据的目的地址
int demo_resolve_address(struct incom_addr *addr, coap_address_t *coapaddr)
参数1: 为目的地址,可以是ipv6或者Ipv4
参数2:为sockaddr的结构体
这个函数要实现的的功能就是吧server的地址,放到dst中,并根据是Ip4和ipv6把dst补充完善。包括端口,地址,协议族
2. 保存路径
static int incom_resolve_path(unsigned char *path, incom_list_t **optlist)
参数1:为访问地址的uri-path 和uri_query组成的字符串
参数2:为一个链表结构体,会通过下面的函数将uri_path和uri_query插入到俩女表结构体t
coap_insert(optlist, new_option_node(COAP_OPTION_URI_PATH, COAP_OPT_LENGTH(b), COAP_OPT_VALUE(b)),order_opts);
coap_insert(optlist, new_option_node(COAP_OPTION_URI_QUERY, COAP_OPT_LENGTH(b), COAP_OPT_VALUE(b)),order_opts);
3.生成ctx结构体
static coap_context_t *incom_new_contex(coap_address_t *coapaddr)
参数1:为第一个函数生成的coap的地址
返回值为ctx结构体
该函数的功能
利用出现的函数生成ctx的结构体
static coap_context_t *incom_gen_context(const char *node, const char *port)
引用ctx = incom_gen_context("::","");
然后利用下面的函数将返回函数添加到ctx中去
static int incom_register_handler(coap_context_t *ctx, coap_response_handler_t handler)
ret = incom_register_handler(ctx, incom_response_handler);
typedef struct coap_context_t {
coap_opt_filter_t known_options;
struct coap_resource_t *resources; /**< hash table or list of known resources */
#ifndef WITHOUT_ASYNC
/**
* list of asynchronous transactions */
struct coap_async_state_t *async_state;
#endif /* WITHOUT_ASYNC */
/**
* The time stamp in the first element of the sendqeue is relative
* to sendqueue_basetime. */
coap_tick_t sendqueue_basetime;
coap_queue_t *sendqueue;
coap_endpoint_t *endpoint; /**< the endpoint used for listening */
#ifdef WITH_POSIX
int sockfd; /**< send/receive socket */
#endif /* WITH_POSIX */
#ifdef WITH_CONTIKI
struct uip_udp_conn *conn; /**< uIP connection object */
struct etimer retransmit_timer; /**< fires when the next packet must be sent */
struct etimer notify_timer; /**< used to check resources periodically */
#endif /* WITH_CONTIKI */
#ifdef WITH_LWIP
uint8_t timer_configured; /**< Set to 1 when a retransmission is
* scheduled using lwIP timers for this
* context, otherwise 0. */
#endif /* WITH_LWIP */
/**
* The last message id that was used is stored in this field. The initial
* value is set by coap_new_context() and is usually a random value. A new
* message id can be created with coap_new_message_id().
*/
unsigned short message_id;
/**
* The next value to be used for Observe. This field is global for all
* resources and will be updated when notifications are created.
*/
unsigned int observe;
coap_response_handler_t response_handler;
ssize_t (*network_send)(struct coap_context_t *context,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
unsigned char *data, size_t datalen);
ssize_t (*network_read)(coap_endpoint_t *ep, coap_packet_t **packet);
}coap_context_t
4.对监听端点设置优先级
ret = incom_set_message_priority(ctx->endpoint->handle.fd, (unsigned int)para->priority);
参数1:为ctx的套接字fd,
参数2:为优先级
通过下面的函数对fd进行优先级设置
ret = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void *)&(priority), sizeof(priority));
5. 组成coap的数据包
static coap_pdu_t *incom_new_request(coap_context_t *ctx, unsigned char m, incom_token *token, incom_list_t **opts, unsigned char *data, size_t len)
参数1:为ctx,上面的函数生成
参数2: 是用于coap头部的code的内容
参数3:是用于coap头部的token的值
参数4:适用于coap头部的opt选项
参数5:为负载数据
参数6:为数据的长度
先利用下面的函数产生一个空的pdu
pdu = coap_new_pdu();
再利用下面的函数向pdu中添加值
pdu->hdr->type = COAP_MESSAGE_CON;
pdu->hdr->id = coap_new_message_id(ctx);
pdu->hdr->code = m;
coap_add_token(pdu, token->len, token->token)
coap_add_option(pdu, COAP_OPTION_KEY(*o), COAP_OPTION_LENGTH(*o), COAP_OPTION_DATA(*o))
coap_add_data(pdu, len, data)
结构体coap_pdu_t
typedef struct {
size_t max_size; /**< allocated storage for options and data */
coap_hdr_t *hdr; /**< Address of the first byte of the CoAP message.
* This may or may not equal (coap_hdr_t*)(pdu+1)
* depending on the memory management
* implementation. */
unsigned short max_delta; /**< highest option number */
unsigned short length; /**< PDU length (including header, options, data) */
unsigned char *data; /**< payload */
#ifdef WITH_LWIP
struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside
* inside the pbuf's payload, but this pointer
* has to be kept because no exact offset can be
* given. This field must not be accessed from
* outside, because the pbuf's reference count
* is checked to be 1 when the pbuf is assigned
* to the pdu, and the pbuf stays exclusive to
* this pdu. */
#endif
} coap_pdu_t;
6.发送数据包
static int incom_send_request(coap_context_t *ctx, coap_endpoint_t *loif, coap_address_t *dst, coap_pdu_t *pdu)
参数1:为上面生成的ctx
参数2:为ctx的端点
参数3:为目的地址dst
参数4:为数据包pdu
7.等待发送完成
ret = incom_wait_response(ctx, para->timeout);
参数1,为上面生成的ctx
参数2:为超时时间