引自维基百科上的介绍,用的是谷歌翻译。。。javascript
受约束的应用协议(COAP)是一种软件协议旨在以很是简单的电子设备,使他们可以在互联网上进行交互式通讯中使用。它特别针对小型低功率传感器,开关,阀门和须要被控制或监督远程,经过标准的Internet网络相似的组件。 COAP是一个应用层协议,该协议是用于在资源受限的网络链接设备,例如无线传感器网络节点使用。 COAP被设计为容易地转换为HTTP与Web简化集成,同时也能知足特殊的要求,例如多播支持,很是低的开销,和简单性。多播,低开销,以及简单性是因特网极其重要物联网(IOT)和机器对机器(M2M)设备,这每每是积重难返,有太多的内存和电源,比传统的互联网设备有。所以,效率是很是重要的。 COAP能够在支持UDP或UDP的模拟大多数设备上运行。html
简单地来讲,CoAP是简化了HTTP协议的RESTful API,于是也只提供了REST的四个方法,即PUT,GET,POST和DELETE。对于微小的资源受限,在资源受限的通讯的IP的网络,HTTP不是一种可行的选择。它占用了太多的资源和太多的带宽。而对于物联网这种嵌入式设备来讲,关于资源与带宽,是咱们须要优先考虑的内容。java
为了测试测试咱们的代码是不是正确工做,咱们须要一个CoAP的命令行工具。目前有两个不错的工具可使用。node
安装命令以下git
bashnpm install coap-cli -g
在coap-cli中,一共有四个方法。分别表示REST的四种不一样的方式:github
bashCommands: get performs a GET request put performs a PUT request post performs a POST request delete performs a DELETE request
在这里,咱们用coap://vs0.inf.ethz.ch/来做一个简单的测试sql
bashcoap get coap://vs0.inf.ethz.ch/ (2.05) ************************************************************ I-D
测试一下如今的最小的物联网系统CoAP版数据库
bashcoap get coap://iot-coap.phodal.com/id/1 (2.05) [{"id":1,"value":"is id 1","sensors1":19,"sensors2":20}]
Mac OS下能够直接用npm
bashbrew install libcoap
Ubuntu GNU/Linux下json
Windows 下
安装完libcoap,咱们能够直接用自带的两个命令
bashcoap-client coap-server
1.用coap-server启一个CoAP服务
bashcoap-server
2.客户端获取数据
bashcoap-client -m get coap://localhost
返回结果
bashv:1 t:0 tkl:0 c:1 id:37109 This is a test server made with libcoap (see http://libcoap.sf.net) Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
为了能访问coap://localhost/,因而咱们便须要安装一个Firefox并安装一个名为Copper的插件。
下载地址: https://addons.mozilla.org/en-US/firefox/addon/copper-270430/
做为测试咱们一样能够访问 coap://vs0.inf.ethz.ch:5683/
接着咱们便开始试试作一个简单的CoAP协议的应用:
这里用到的是一个Nodejs的扩展Node-CoAP
node-coap is a client and server library for CoAP modelled after the http module.
Node-CoAP是一个客户端和服务端的库用于CoAP的模块建模。建立一个package.json文件,添加这个库
javascript{ "dependencies":{ "coap": "0.7.2" } }
接着执行
bashnpm install
就能够安装好这个库。若是遇到权限问题,请用
bashsudo npm install
接着,建立这样一个app.js
javascriptconst coap = require('coap') , server = coap.createServer() server.on('request', function(req, res) { res.end('Hello ' + req.url.split('/')[1] + '\n') }) server.listen(function() { console.log('server started') })
执行
bashnode app.js
即可以在浏览器上访问了,由于如今什么也没有,因此什么也不会返回。
接着下来再建立一个client端的js,并运行之
javascriptconst coap = require('coap') , req = coap.request('coap://localhost/World') req.on('response', function(res) { res.pipe(process.stdout) }) req.end()
就能够在console上输出
bashHello World
也就达到了咱们的目的,用CoAP协议建立一个服务,接着咱们应该用它建立更多的东西,如产生JSON数据,以及RESTful。和HTTP版的最小物联网系统同样,CoAP版的最小物联网系统也是要返回JSON的。
这说里NodeJS Module的意义是由于咱们须要在别的地方引用到db_helper这个库,也就是下一小节要的讲的内容。
这样咱们就能够在server.js相似于这样去引用这个js库。
javascriptvar DBHelper = require('./db_helper.js'); DBHelper.initDB();
而这样调用的前提是咱们须要去声明这样的module,为了方便地导出函数功能调用。
javascriptfunction DBHelper(){ } DBHelper.initDB = function(){}; module.exports = DBHelper;
此次咱们用的是SQLite3(你能够用MySQL,出于安全考虑用SQLite3,SQLite3产生的是一个文件)。一个简单的initDB函数
javascriptvar db = new sqlite3.Database(config["db_name"]); var create_table = 'create table if not exists basic (' + config["db_table"] + ');'; db.serialize(function() { db.run(create_table); _.each(config["init_table"], function(insert_data) { db.run(insert_data); }); }); db.close();
首先从配置中读取db_name,接着建立table,而后调用underscore的each方法,建立几个数据。配置以下所示
javascriptconfig = { "db_name": "iot.db", "db_table": "id integer primary key, value text, sensors1 float, sensors2 float", "init_table":[ "insert or replace into basic (id,value,sensors1,sensors2) VALUES (1, 'is id 1', 19, 20);", "insert or replace into basic (id,value,sensors1,sensors2) VALUES (2, 'is id 2', 20, 21);" ], "query_table":"select * from basic;" };
而以前所提到的url查询所作的事情即是
javascriptDBHelper.urlQueryData = function (url, callback) { var db = new sqlite3.Database("iot.db"); var result = []; console.log("SELECT * FROM basic where " + url.split('/')[1] + "=" + url.split('/')[2]); db.all("SELECT * FROM basic where " + url.split('/')[1] + "=" + url.split('/')[2], function(err, rows) { db.close(); callback(JSON.stringify(rows)); }); };
将URL传进来,便解析这个参数,接着再放到数据库中查询,再回调回结果。这样咱们就能够构成以前所说的查询功能,而咱们所谓的post功能彷佛也能够用一样的方法加进去。
简单地记录一下在IoT-CoAP中一次获取数据地过程。
先看看在示例中的Get.js的代码,这关乎在后面server端的代码。
javascriptconst coap = require('coap') ,requestURI = 'coap://localhost/' ,url = require('url').parse(requestURI + 'id/1/') ,req = coap.request(url) ,bl = require('bl'); req.setHeader("Accept", "application/json"); req.on('response', function(res) { res.pipe(bl(function(err, data) { var json = JSON.parse(data); console.log(json); })); }); req.end();
const定义数据的方法,和咱们在其余语言中有点像。只是这的const主要是为了程序的健壮型,减小程序出错,固然这不是javascript的用法。
咱们构建了一个请求的URL
bashcoap://localhost/id/1/
咱们对咱们的请求添加了一个Header,内容是Accept,值是'application/json'也就是JSON格式。接着,即是等待请求回来,再处理返回的内容。
判断请求的方法
在这里先把一些无关的代码删除掉,并保证其能工做,so,下面就是简要的逻辑代码。
javascriptvar coap = require('coap'); var server = coap.createServer({}); var request_handler = require('./request_handler.js'); server.on('request', function(req, res) { switch(req.method){ case "GET": request_handler.getHandler(req, res); break; } }); server.listen(function() { console.log('server started'); });
建立一个CoAP服务,判断req.method,也就是请求的方法,若是是GET的话,就调用request_handler.getHandler(req, res)。而在getHandler里,判断了下请求的Accept
javascriptrequest_helper.getHandler = function(req, res) { switch (req.headers['Accept']) { case "application/json": qh.returnJSON(req, res); break; case "application/xml": qh.returnXML(req, res); break; } };
若是是json刚调用returnJSON,
Database与回调
而这里为了处理回调函数刚分为了两部分
javascriptquery_helper.returnJSON = function(req, res) { DBHelper.urlQueryData(req.url, function (result) { QueryData.returnJSON(result, res); }); };
而这里只是调用了
javascriptDBHelper.urlQueryData = function (url, callback) { var db = new sqlite3.Database(config["db_name"]); console.log("SELECT * FROM basic where " + url.split('/')[1] + "=" + url.split('/')[2]); db.all("SELECT * FROM basic where " + url.split('/')[1] + "=" + url.split('/')[2], function(err, rows) { db.close(); callback(JSON.stringify(rows)); }); };
这里调用了node sqlite3去查询对应id的数据,用回调处理了数据没法到外部的问题,而上面的returnJSON则只是返回最后的结果,code以及其余的内容。
javascriptQueryData.returnJSON = function(result, res) { if (result.length == 2) { res.code = '4.04'; res.end(JSON.stringify({ error: "Not Found" })); } else { res.code = '2.05'; res.end(result); } };
当resulst的结果为空时,返回一个404,由于没有数据。这样咱们就构成了整个的链,再一步步返回结果。
在IoT-CoAP中咱们使用到了一个Block2的东西,因而便整理相关的一些资料,做一个简单的介绍,以及在代码中的使用。
CoAP是一个RESTful传输协议用于受限设备的节点和网络。基本的CoAP消息是一个不错的选择对于小型载荷如
然而,有时咱们的应用须要传输更大的有效载荷,如——更新固件。与HTTP,TCP作繁重工做将大型有效载荷分红多个数据包,并确保他们全部到达并以正确的顺序被处理。
CoAP是同UDP与DLTS同样是基于数据报传输的,这限制了资源表示(resource representation)的最大大小,使得传输不须要太多的分割。虽然UDP支持经过IP分片传输更大的有效载荷,且仅限于64KiB,更重要的是,并无真正很好地约束应用和网络。
而不是依赖于IP分片,这种规范基本COAP了对“块”选项,用于传输信息从多个资源区块的请求 - 响应对。在许多重要的状况下,阻止使服务器可以真正无状态:服务器能够处理每块分开传输,而无需创建链接之前的数据块传输的其余服务器端内存。
综上所述,块(Block)选项提供了传送一个最小的在分块的方式更大的陈述。
看看在IoT CoAP中的post示例。
javascriptconst coap = require('coap') ,request = coap.request ,bl = require('bl') ,req = request({hostname: 'localhost',port:5683,pathname: '',method: 'POST'}); req.setOption('Block2', [new Buffer('1'),new Buffer("'must'"), new Buffer('23'), new Buffer('12')]); req.setHeader("Accept", "application/json"); req.on('response', function(res) { res.pipe(bl(function(err, data) { console.log(data); process.exit(0); })); }); req.end();
Block2中一共有四个数据,相应的数据结果应该是
javascript{ name: 'Block2', value: <Buffer 31> } { name: 'Block2', value: <Buffer 27 6d 75 73 74 27> } { name: 'Block2', value: <Buffer 32 33> } { name: 'Block2', value: <Buffer 31 32> }
这是没有解析的Block2,简单地能够用
javascript_.values(e).toString()
将结果转换为
Block2,1
Block2,'must'
Block2,23
Block2,12
接着按","分开,
javascript_.values(e).toString().split(',')[1]
就有
bash[ '1', '\'must\'', '23', '12' ]
即可以很愉快地将其post到数据库中了,
在作IoT-CoAP的过程当中只支持JSON,查阅CoAP的草稿时发现支持了诸多的Content Types。
如下文字来自谷歌翻译:
互联网媒体类型是经过HTTP字符串标识,如“application/xml”。该字符串是由一个顶层的类型“applicaion”和子类型的“XML”。为了尽可能减小使用这些类型的媒体类型来表示的开销消息有效载荷,COAP定义一个标识符编码方案互联网媒体类型的子集。预计这桌将可扩展标识符的值的IANA维护。内容类型选项被格式化为一个8位无符号整数。初始映射到一个合适的互联网媒体类型标识符表所示。复合型高层次类型(multipart和不支持消息)。标识符值是从201-255保留的特定于供应商的,应用程序特定的或实验使用和不禁IANA。
下面是HTTP的标识符及类型
Internet media type | Identifier |
---|---|
text/plain (UTF-8) | 0 |
text/xml (UTF-8) | 1 |
text/csv (UTF-8) | 2 |
text/html (UTF-8) | 3 |
image/gif | 21 |
image/jpeg | 22 |
image/png | 23 |
image/tiff | 24 |
audio/raw | 25 |
video/raw | 26 |
application/link-format [I-D.ietf-core-link-format] | 40 |
application/xml | 41 |
application/octet-stream | 42 |
application/rdf+xml | 43 |
application/soap+xml | 44 |
application/atom+xml | 45 |
application/xmpp+xml | 46 |
application/exi | 47 |
application/x-bxml | 48 |
application/fastinfoset | 49 |
application/soap+fastinfoset | 50 |
application/json | 51 |
而在CoAP中只有简单地几个
Media type | Encoding | Id. | Reference |
---|---|---|---|
text/plain; | - | 0 | [RFC2046][RFC3676][RFC5147] |
charset=utf-8 | |||
application/ | - | 40 | [RFC6690] |
link-format | |||
application/xml | - | 41 | [RFC3023] |
application/ | - | 42 | [RFC2045][RFC2046] |
octet-stream | |||
application/exi | - | 47 | [EXIMIME] |
application/json | - | 50 | [RFC4627] |
简单地说就是:
诸如application/json的Content Types在CoAP中应该是50
。如上表所示的结果是其对应的结果,这样的话能够减小传递的信息量。
因而在一开始的时候首先支持的即是"application/json"这样的类型。
首先判断请求的header
javascriptrequest_helper.getHandler = function(req, res) { switch (req.headers['Accept']) { case "application/json": qh.returnJSON(req, res); break; case "application/xml": qh.returnXML(req, res); break; } };
再转至相应的函数处理,而判断的依据则是Accept是否是"application/json"。
javascriptregisterFormat('text/plain', 0) registerFormat('application/link-format', 40) registerFormat('application/xml', 41) registerFormat('application/octet-stream', 42) registerFormat('application/exi', 47) registerFormat('application/json', 50)
对应地咱们须要在一发出请求的时候设置好Accept,要不就没有办法返回咱们须要的结果。
javascriptreq.setHeader("Accept", "application/json");
返回JSON
在给IoT CoAP添加了JSON支持以后,变得很是有意思,至少咱们能够得到咱们想要的结果。在上一篇中咱们介绍了一些经常使用的工具——CoAP 命令行工具集。
CoAP客户端代码
开始以前咱们须要有一个客户端代码,以便咱们的服务端能够返回正确的数据并解析
javascriptvar coap = require('coap'); var requestURI = 'coap://localhost/'; var url = require('url').parse(requestURI + 'id/1/'); console.log("Request URL: " + url.href); var req = coap.request(url); var bl = require('bl'); req.setHeader("Accept", "application/json"); req.on('response', function(res) { res.pipe(bl(function(err, data) { var json = JSON.parse(data); console.log(json); })); }); req.end();
代码有点长内容也有点多,可是核心是这句话:
javascriptreq.setHeader("Accept", "application/json");
这样的话,咱们只须要在咱们的服务端一判断,
javascriptif(req.headers['Accept'] == 'application/json') { //do something };
这样就能够返回数据了
CoAP Server端代码
Server端的代码比较简单,判断一下
javascriptif (req.headers['Accept'] == 'application/json') { parse_url(req.url, function(result){ res.end(result); }); res.code = '2.05'; }
请求的是不是JSON格式,再返回一个205,也就是Content,只是这时设计是请求一个URL返回对应的数据。如
bashcoap://localhost/id/1/
这时应该请求的是ID为1的数据,即
javascript[ { id: 1, value: 'is id 1', sensors1: 19, sensors2: 20 }]
而parse_url只是从数据库从读取相应的数据。
javascriptfunction parse_url(url ,callback) { var db = new sqlite3.Database(config["db_name"]); var result = []; db.all("SELECT * FROM basic;", function(err, rows) { callback(JSON.stringify(rows)); }) }
而且所有都显示出来,设计得真是有点不行,不过如今已经差很少了。
在线查看:一步步搭建物联网系统
图灵-电子书版一步步搭建物联网系统