基于STM32平台的CoAP Server方案
CoAP是受限制的应用协议(Constrained Application Protocol)的代名词。在当前由PC机组成的世界,信息交换是通过TCP和应用层协议HTTP实现的。但是对于小型设备而言,实现TCP和HTTP协议显然是一个过分的要求。为了让小设备可以接入互联网,CoAP协议被设计出来。CoAP是一种应用层协议,它运行于UDP协议之上而不是像HTTP那样运行于TCP之上。CoAP协议非常小巧,最小的数据包仅为4字节。
本文将使用STM32平台实现一个CoAP Server Demo。本文将详细说明如何使用STM32这样的低成本MCU实现CoAP Server的步骤,本文试图说明CoAP协议虽然很“年轻”,但是有用、好用且易用。
【代码仓库】
如果想获得本文的示例代码请点击——【bitbucket】,示例代码中的doc目录有本文所使用开发板的原理图和相关说明。
【相关博文】
【物联网学习笔记——索引博文】
【CoAP学习笔记——nodeJS node-coap安装和使用(windows平台)】
1.使用LwIP处理CoAP数据包
新建一个套接字,绑定UDP 5683端口,侦听该端口数据使用microcoap响应函数解析,最后获得返回结果即可。示例中使用了RT Thread中移植好的LwIP协议栈,网卡驱动为ENC28J60。
- voidcoap_server(void*para)
- {
- intfd;
- structsockaddr_inservaddr,cliaddr;
- coap_rw_buffer_tscratch_buf={scratch_raw,sizeof(scratch_raw)};
- if((fd=socket(AF_INET,SOCK_DGRAM,0))==-1)
- {
- printf("SocketErrorrn");
- return;
- }
- servaddr.sin_family=AF_INET;
- servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
- servaddr.sin_port=htons(PORT);
- rt_memset(&(servaddr.sin_zero),0,sizeof(servaddr.sin_zero));
- if((bind(fd,(structsockaddr*)&servaddr,sizeof(servaddr)))==-1)
- {
- printf("Binderrorrn");
- return;
- }
- endpoint_setup();
- rt_kprintf("CoapServerStart!rn");
- while(1)
- {
- intn,rc;
- socklen_tlen=sizeof(cliaddr);
- coap_packet_tpkt;
- n=recvfrom(fd,buf,sizeof(buf),0,(structsockaddr*)&cliaddr,&len);
- #ifdefMICROCOAP_DEBUG
- printf("rn--------------------rn");
- printf("ReceivedBuffer:rn");
- coap_dump(buf,n,true);
- printf("rn");
- #endif
- if(0!=(rc=coap_parse(&pkt,buf,n)))
- {
- printf("Badpacketrc=%drn",rc);
- }
- else
- {
- size_trsplen=sizeof(buf);
- coap_packet_trsppkt;
- #ifdefMICROCOAP_DEBUG
- printf("DumpPacket:rn");
- coap_dumpPacket(&pkt);
- #endif
- coap_handle_req(&scratch_buf,&pkt,&rsppkt);
- if(0!=(rc=coap_build(buf,&rsplen,&rsppkt)))
- {
- printf("coap_buildfailedrc=%dn",rc);
- }
- else
- {
- #ifdefMICROCOAP_DEBUG
- printf("--------------------rn");
- printf("SendingBuffer:rn");
- coap_dump(buf,rsplen,true);
- printf("rn");
- #endif
- #ifdefMICROCOAP_DEBUG
- coap_dumpPacket(&rsppkt);
- #endif
- sendto(fd,buf,rsplen,0,(structsockaddr*)&cliaddr,sizeof(cliaddr));
- }
- }
- }
- }
代码中使用了多个LwIP Socket部分的函数,例如socket, bind, recvfrom, sendto等。
其中coap_parse函数把从UDP获得的payload转化为符合CoAP规范的结构体,coap_handle_req函数根据CoAP请求中的URI,调用响应的处理函数。最后由coap_build函数把处理的结果系列化为UDP负载。
2.终端描述
所有的终端信息均保存在endpoints全局数组中,该全局数组位于endpoints.c文件中。
- constcoap_endpoint_tendpoints[]=
- {
- {COAP_METHOD_GET,handle_get_well_known_core,&path_well_known_core,"ct=40"},
- {COAP_METHOD_GET,handle_get_light,&path_light,"ct=0"},
- {COAP_METHOD_PUT,handle_put_light,&path_light,NULL},
- {COAP_METHOD_GET,handle_get_test_json,&path_test_json,"ct=50"},
- {(coap_method_t)0,NULL,NULL,NULL}
- };
【1】每个endpoint需要CoAP访问方法,相应的处理函数,URI路径描述,资源描述方法等。
【2】CoAP协议中定义了多种访问方法,GET、PUT、POST和DELETE等方法。
【3】handle_get_light等函数主要用于处理CoAP请求,根据不同的请求调用不同的处理方法。
【4】ct=xx指定资源描述方法,例如ct=0表示字符串形式描述,ct=50表示JSON形式描述。
URI采用以下方式描述:
- staticinthandle_get_light(coap_rw_buffer_t*scratch,
- constcoap_packet_t*inpkt,
- coap_packet_t*outpkt,
- uint8_tid_hi,uint8_tid_lo)
- {
- returncoap_make_response(scratch,
- outpkt,
- (constuint8_t*)&light,1,
- id_hi,id_lo,
- &inpkt->tok,
- COAP_RSPCODE_CONTENT,
- COAP_CONTENTTYPE_TEXT_PLAIN);
- }
除了指定返回内容之外,可通过COAP_RSPCODE_CONTENT指定返回是否成功,也可以通过COAP_CONTENTTYPE_TEXT_PLAIN指定返回内容的格式。更多的定义请查看microcoap的源代码。
3.简单测试
可使用CoAP命令行工具测试CoAP Server工作是否正常,或者使用火狐浏览器的coap插件。
使用CoAP命令行测试工具——coap-cli,详细的安装步骤请参考【CoAP学习笔记——nodeJS node-coap安装和使用(windows平台)】第2部分
3.1 light Demo
输入指令,尝试修改light状态
coap put -p 1 coap://10.13.11.116/light
返回
(2.05) 1
说明
-p参数可用于指定coap的负载,此处1表示打开light,0表示关闭light。
图3.1 light PUT方法输出
输入指令,尝试获得light状态
coap get coap://10.13.11.116/light
返回
(2.05) 1
控制台输出
图3.2 light GET方法输出
3.2 JSON格式Demo
指令
coap get coap://10.13.11.116/test_json
返回
(2.05)
{
"value": 12
}
控制台输出
图3.3 JSON格式测试输出
4.CoAP格式分析
通过示例代码并借助wireshark可分析CoAP数据包的各个部分,可加上CoAP协议的理解。wireshark中已经支持CoAP协议,在过滤窗口中输入coap便可抓取所有coap数据包。
CoAP协议的分析请参考——【CoAP学习笔记——CoAP格式详解】
图4.1 wireshark分析CoAP
5. 总结
microcoap正如它的名称一样,简单好用,函数不多但是可以实现最基本的功能。(by xukai871105)
评论