Coap协议(1)入门简介

一、Coap协议开发

Coap(Constrained Application Protocol)是一种在物联网世界的类web协议,它的详细规范定义在 RFC 7252。COAP名字翻译来就是“受限应用协议”,顾名思义,使用在资源受限的物联网设备上。物联网设备的ram,rom都通常非常小,运行TCP和HTTP是不可以接受的。

Coap协议(1)入门简介_第1张图片

1、Coap协议介绍

1.1、Coap协议特点
  • COAP协议网络传输层由TCP改为UDP。
  • 它基于REST,server的资源地址和互联网一样也有类似url的格式,客户端同样有POST,GET,PUT,DELETE方法来访问server,HTTP做了简化。
  • COAP是二进制格式的,HTTP是文本格式的,COAP比HTTP更加紧凑。
  • 轻量化,COAP最小长度仅仅4B,一个HTTP的头都几十个B了。
  • 支持可靠传输,数据重传,块传输。确保数据可靠到达。
  • 支持IP多播,即可以同时向多个设备发送请求。
  • 非长连接通信,适用于低功耗物联网场景。
1.2、Coap协议消息类型

COAP协议有4种消息类型

  • CON—— 需要被确认的请求,如果CON请求被发送,那么对方必须做出响应。这有点像TCP,对方必须给确认收到消息,用以可靠消息传输。
  • NON—— 不需要被确认的请求,如果NON请求被发送,那么对方不必做出回应。这适用于消息会重复频繁的发送,丢包不影响正常操作。这个和UDP很像。用以不可靠消息传输。
  • ACK —— 应答消息,对应的是CON消息的应答。
  • RST —— 复位消息,可靠传输时候接收的消息不认识或错误时,不能回ACK消息,必须回RST消息。
1.3、Coap消息格式

CoAP的消息格式是很紧凑的,默认运行在UDP上(每个CoAP消息都是UDP数据包中的数据部分)。
CoAP也可以运行在DTLS协议上和其它传输协议上,例如SMS,TCP或SCTP(CoAP不支持UDP-lite[RFC3828]和UDP zero checksum[RFC6936])。

CoAP消息用二进制格式进行编码。 这个消息格式以一个固定4个字节的头部开始
此后是一个长度在0到8字节之间的Token。Token值之后是0个或多个Type-Length-Value(TLV)格式的选项(Option)。之后到整个数据报的结尾都是payload部分,payload可以为空。

Coap协议(1)入门简介_第2张图片

头部字段定义如下:

  • 版本号(Ver)
    2-bit无符号整型,代表CoAP版本号。本文档(7252)的实现必须设置这个字段为0b01。其它的值为今后其它版本保留。对于带有未知版本号的消息,必须忽略。

  • 类型(T)
    2-bit无符号整型。代表这个消息的类型是:CON(0), NON(1), ACK(2),或RST(3)

  • Token长度(TKL)
    4-bit无符号整型。表示变长的Token字段(0-8字节)的长度。长度9-15是保留的,不能设置长度为9-15。如果设置了长度为9-15,必须被当作消息格式错误来处理。

  • 列代码(Code)
    8-bit无符号整型。拆分为3-bit的分类信息和5-bit详细信息
    写作”c.dd”。c是3-bit长,可以是一个从0到7的数字,dd是5-bit长,它一个两位的数字,从00到31。
    分类信息c可以代表是一个请求(0),一个成功的响应(2),一个客户端错误响应(4),或者一个服务端错误响应(5)。
    所有其它的值都是保留的。代码0.00是一个特殊的情况,表示一个空的消息。当消息是一个请求时,Code字段表示请求方法。当响应时,Code字段代表响应代码。Code字段所有可取的值都在下文CoAP代码表中定义了。

  • 消息ID(Message ID)
    16-bit无符号整型,网络字节序。用于检测消息重复以及匹配ACK/RST类型的消息和CON/NON类型的消息。生成消息ID和匹配消息的规则在第4章中讲述。

  • Token值
    头部之后是Token值,可以有0到8个字节,由Token长度字段指定。这个Token值用于将某个请求和对应的响应关联。

  • Options
    头部和Token之后,是0个或多个选项(见3.1节)。一个选项之后,有可能是消息结束,也可能是另一个选项,也可能是payload标识符和payload部分。

  • payload部分
    在头部、token和选项之后,是payload部分(可以没有payload)。
    如果有payload,并且长度不为0,那么payload之前有一个固定长度为一个字节的payload标识符(0xFF),它标志着选项部分的结束和payload部分的开始
    payload部分从标识符之后开始,一直到这个UDP数据报结束,也就是说,payload部分的长度可以根据UDP数据报的长度计算出来。
    如果没有payload标识符,那么就代表这是一个0长度的payload。如果存在payload标识符但其后跟随的是0长度的payload,那么必须当作消息格式错误处理。

    Coap负载包含与具体应用直接相关的内容,Coap负载包含多种不同的媒体类型,包括二进制负载、文本负载、XML负载、JSON负载、CBOR负载等。Coap所支持的媒体类型中并不包含HTML类型。

实现注意:0xFF这个值有可能出现在一个选项的长度或选项的值中,所以简单的扫描0xFF来寻找payload标识符是不可行的。作为payload标识符的0xFF只可能出现在一个选项结束之后下一个选项有可能开始的地方。

1.4、Coap代码注册

方法码(Method Codes) 这个sub-registry是“CoAP Method Codes” 每次进入这个sub-registry都必须包含在0.01-0.31范围内的Method Code,方法的名字,方法文档的参考。
初始化进入这个sub-registry如下:

     +------+--------+-----------+---------------+                       
     | Code | Name   | Reference |  description  |           
     +------+--------+-----------+---------------+                        
     | 0.01 | GET    | [RFC7252] |  用于获得某资源  |                    
     | 0.02 | POST   | [RFC7252] |  用于创建某资源  |                    
     | 0.03 | PUT    | [RFC7252] |  用于更新某资源  |                   
     | 0.04 | DELETE | [RFC7252] |  用于删除某资源  |                   
     +------+--------+-----------+----------------+
                表 5: CoAP Method Codes

其他Method Codes没有安排。每个不能被服务器识别或未被服务器支持的方法通常会导致一个4.05响应码。

互联网号码分配政策在未来为这个sub-registry额外定义描述在“IETF Review or IESG Approval” [RFC5226].

方法代码的文档需要指定这个请求的语义,包含如下属性:

  • 1.这个方法的响应码成功返回。
  • 2.这个方法是否幂等,安全或两者都满足。

响应码 这个sub-registry的名字是“CoAP Response Codes”
每个sub-registry必须包含在2.00-5.31范围内的响应码,响应码的描述,响应码的文档参考。

初始化进入这个sub-registry如下:

+------+------------------------------+-----------+ 
   | Code | Description                  | Reference |
   +------+------------------------------+-----------+
   | 2.01 | Created                      | [RFC7252] | 
   | 2.02 | Deleted                      | [RFC7252] |
   | 2.03 | Valid                        | [RFC7252] |
   | 2.04 | Changed                      | [RFC7252] |
   | 2.05 | Content                      | [RFC7252] |
   | 4.00 | Bad Request                  | [RFC7252] |
   | 4.01 | Unauthorized                 | [RFC7252] | 
   | 4.02 | Bad Option                   | [RFC7252] |
   | 4.03 | Forbidden                    | [RFC7252] | 
   | 4.04 | Not Found                    | [RFC7252] | 
   | 4.05 | Method Not Allowed           | [RFC7252] | 
   | 4.06 | Not Acceptable               | [RFC7252] | 
   | 4.12 | Precondition Failed          | [RFC7252] | 
   | 4.13 | Request Entity Too Large     | [RFC7252] |  
   | 4.15 | Unsupported Content-Format   | [RFC7252] |  
   | 5.00 | Internal Server Error        | [RFC7252] |
   | 5.01 | Not Implemented              | [RFC7252] | 
   | 5.02 | Bad Gateway                  | [RFC7252] |  
   | 5.03 | Service Unavailable          | [RFC7252] | 
   | 5.04 | Gateway Timeout              | [RFC7252] | 
   | 5.05 | Proxying Not Supported       | [RFC7252] | 
   +------+------------------------------+-----------+ 
             表 6: CoAP Response Codes

响应码3.00-3.31是预留给将来使用。所有其他响应码都没有被安排。

互联网号码分配政策为这个sub-registry以后额外的定义描述在“IETF Review or IESG Approval”[RFC5226].

响应码的文档需要指定这个响应的语义,包含如下属性:

  • 响应码应用方式。
  • 是否需要携带payload,option。
  • payload的语义。举个例子,2.05(内容)响应的payload是目标资源的展示;payload在错误的响应中是可读和诊断的。
  • payload的格式。举个例子,这个格式在2.05(内容)响应是通过内容格式选项表示;payload的格式在一个错误的
  • 响应中总是Net-Unicode文本
  • 响应是否可以缓冲,取决于freshness model
  • 响应是否通过合法性检查,取决于validation model
  • 响应是否导致一个cache来标志响应已经存储,表明这个请求的URI不是最新的。
1.5、Coap媒体类型

Content-Format编号内容

  • 【text/plain】 编号为0,表示负载为字符串形式,默认为UTF8编码。
  • 【application/link-format】编号为40,CoAP资源发现协议中追加定义,该媒体类型为CoAP协议特有。
  • 【application/xml】编号为41,表示负载类型为XML格式。
  • 【application/octet-stream】编号为42,表示负载类型为二进制格式。
  • 【application/exi】编号为47,表示负载类型为“精简XML”格式。
  • 另外,还有一种格式也北IANA认定,也会在CoAP协议中广泛使用那便是CBOR格式,该格式可理解为二进制JSON格式。
  • 【applicaiton/cbor】编号为60。
1.5、Coap的URL

coap的url和HTTP的有很相似的地方,开头是“coap”对应“http”或者“coaps”对应“https”。

HTTP的默认端口是tcp 80,coap的默认端口是udp 5683(coaps是5684)。

2、Californium框架介绍

Californium框架是一款基于Java实现的Coap技术框架,该项目实现了Coap协议的各种请求响应定义,支持CON/NON不同的可靠性传输模式。Californium 基于分层设计且高度可扩展。在同类型的 Coap技术实现中,Californium的性能表现是比较突出的,如下图:

Coap协议(1)入门简介_第3张图片

Californiium 定义了三层架构

  1. 网络层,负责处理端口监听,网络数据收发;
  2. 协议层,负责Coap协议数据包解析及封装,实现消息的路由、可靠性传输、Token处理、观察者模型等等;
  3. 逻辑层,负责 Resource定义和映射,一个Resource 对应一个URL,可独立实现Coap 请求处理。为了便于理解,可以将resource是为一个servlet或者controller。

对于我们来讲,开发工作主要在逻辑层。

三层架构中都可以支持独立的线程池,其中网络层与协议层的线程池保持独立;

逻辑层可为每个Resource指定独立的线程池,并支持父级继承的机制,即当前Resource若没有定义则沿用父级Resource线程池;

若逻辑层未指定线程池,则默认使用协议层的线程池。

2.1、Californium主要接口介绍

Californium框架的使用并不复杂,我们主要是调用逻辑层的一些类,最常用的一些类和接口如下:

  • CoapClient:客户端的入口,客户端通过实现CoapClient向服务端发送数据。
  • CoapServer:服务端的入口,启动服务端,接收客户端传送的数据。
  • Endpoint:定义为一个端点,通常与一个IP和端口对应,其屏蔽了client和server交互时的网络传输细节。对于client来说,Endpoint代表通讯的服务端地址端口;而对于server来说则代表了绑定监听的地址及端口。CoapEndpoint实现了Endpoint接口。
  • Exchange:Exchange描述了请求-响应模型,一个Exchange会对应一个Request,相应的Response,以及当前的Endpoint。
  • CoapResource:最终处理消息的类,通过继承CoapResource类来实现处理客户端发来的请求,通过重写相应的方法处理GET,POST等请求,实现Resource的时候需要指定Resource的名字,这个名字很重要,客户端请求的时候在uri中需要带上Resource的名字,这样框架才会将请求指向对应的Resource。

3、Californium框架的使用示例

示例介绍了一个简单的框架的应用,客户端向服务端发送一段消息,服务端接收并返回接收成功消息。代码基于JDK1.8。

3.1、服务端
import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.server.resources.CoapExchange;

import java.text.SimpleDateFormat;
import java.util.Date;

public class CoapServerTest
{
    public static void main(String[] args) {
        // 主机为localhost 端口为默认端口5683
        final CoapServer server = new CoapServer();

        // 默认就是udp实现传输层
        server.add(new CoapResource("hello"){
            // 创建一个资源为hello 请求格式为 主机:端口\hello
            @Override
            public void handleGET(CoapExchange exchange) {
                //  重写处理GET请求的方法
                exchange.respond(CoAP.ResponseCode.CONTENT, "Hello CoAP!");
            }
        });

        server.add(new CoapResource("time"){
            // 创建一个资源为time 请求格式为 主机:端口\time
            @Override
            public void handleGET(CoapExchange exchange) {
                Date date = new Date();
                exchange.respond(CoAP.ResponseCode.CONTENT,
                        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
            }
        });
        // 启动服务
        server.start();
    }
}
3.2、客户端
import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.Utils;
import org.eclipse.californium.core.coap.MediaTypeRegistry;

import java.net.URI;

public class CoapClientTest {
    public static void main(String[] args) throws Exception {
        hello();
        //time();
    }

    public static void hello() throws Exception {
        URI uri = null;
        // 创建一个资源请求hello资源,注意默认端口为5683
        uri = new URI("localhost:5683/hello");
        CoapClient client = new CoapClient(uri);
        CoapResponse response = client.get();
        if(response !=null){
            // 打印请求状态码
            System.out.println(response.getCode());
            // 选项参数
            System.out.println(response.getOptions());
            // 获取内容文本信息
            System.out.println(response.getResponseText());
            System.out.println("\nAdvanced\n");
            // 打印格式良好的输出
            System.out.println(Utils.prettyPrint(response));
        }
    }


    public static void time() throws Exception {
        URI uri = null;
        // 创建一个资源请求hello资源,注意默认端口为5683
        uri = new URI("localhost:5683/time");
        CoapClient client = new CoapClient(uri);
        CoapResponse response = client.post("", MediaTypeRegistry.TEXT_PLAIN);
        if(response !=null){
            // 打印请求状态码
            System.out.println(response.getCode());
            // 选项参数
            System.out.println(response.getOptions());
            // 获取内容文本信息
            System.out.println(response.getResponseText());
            System.out.println("\nAdvanced\n");
            // 打印格式良好的输出
            System.out.println(Utils.prettyPrint(response));
        }
    }
}

你可能感兴趣的:(【物联网-Coap协议】)