CoAP协议入门解析(一)

目录

  • 一. 什么是CoAP?
  • 二. 报文格式
  • 三. 如何使用?
  • 一. 什么是CoAP?

    Coap(Constrained Application Protocol)受限应用协议。一种在物联网世界的类web协议。顾名思义,使用在资源受限的物联网设备上。

    CoAP是类HTTP协议,它是对HTTP协议简化,协议非常简单,头部和选项字段较少,占用网络带宽和资源较少。对资源受限设备和网络进行优化,具有低能耗和低带宽消耗的特性。

    CoAP HTTP
    服务器资源(地址) coap(s): //ip:端口/URI http(s): //ip:端口/URI
    请求码(请求方式) 0.01/0.02 …等 GET/POST
    响应码 4.00 …等 400 Bad Request
    数据类型 Content-Format:50 …等 Content-Type:application/json
    数据传输 支持可靠传输,数据重传,块传输。( CoAP通过消息类型(见下方说明)来保证) 支持可靠传输,数据重传
    默认端口 coaps:5684/coap:5683(udp端口) https:443/http:80
    安全加密层 DTLS(单播时使用,资源有限) TTL
    数据内容 二进制 文本
    网络层 UDP TCP
    通信方式 IP多播,同时向多个设备请求 (广播只能通过UDP或原始IP实现) 点对点通信
    通信方式 非长连接通信 长连接和短连接都支持

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

    二. 报文格式

      2   2    4          8                     16
    +---+---+-----+----------------+---------------------------|
    |ver| T | TKL |      Code      |        Message ID         |
    +----------------------------------------------------------|
    |   Token(if any, TKL bytes)...                            |
    +----------------------------------------------------------|
    |   Optons(if any)...                                      |
    +---------------+------------------------------------------|
    |1 1 1 1 1 1 1 1|    Payload(if any)...                    |
    +----------------------------------------------------------|
    

    第一行是消息头,必须有,固定4个byte。

    字段 大小 说明
    Ver 2bit 版本信息,当前是必须写0x01。
    T 2bit 消息类型,包括 CON, NON. ACK, RST这4种。
    TKL 4bit token长度, 当前支持0~8B长度,其他长度保留将来扩展用。
    Code 8bit 0代表空消息或者请求码, 分成前3bit(0~7)和后5bit(0 ~31),前3bit代表类型(class type), 后5bit代表细节码(detail code)
    Message ID 16bit 代表消息MID,每个消息都有一个ID ,重发的消息MID不变
    token(可选) 0~8byte 用于将响应与请求匹配。 token值为0到8字节的序列。 ( 每条消息必须带有一个标记, 即使它的长度为零)。 每个请求都带有一个客户端生成的token, 服务器在任何结果响应中都必须对其进行回应。token类似消息ID,用以标记消息的唯一性。token还是消息安全性的一个设置,使用全8字节的随机数,使伪造的报文无法获得验证通过。
    Option 请求消息 与回应消息都可以0~多个options。主要用于描述请求或者响应对应的各个属性,类似参数或者特征描述,比如是否用到代理服务器,目的主机的端口等。
    Payload 实际携带数据内容,若有,前面加payload标识符“0xFF”,如果没有payload标识符,那么就代表这是一个0长度的payload。如果存在payload标识符但其后跟随的是0长度的payload,那么必须当作消息格式错误处理。

    三. 如何使用?

    1.引入依赖(git地址:https://github.com/eclipse-californium/californium)

            <dependency>
                <groupId>org.eclipse.californium</groupId>
                <artifactId>californium-core</artifactId>
                <version>2.0.0-M7</version>
            </dependency>
            <dependency>
                <groupId>org.eclipse.californium</groupId>
                <artifactId>element-connector</artifactId>
                <version>2.0.0-M7</version>
            </dependency>
            <dependency>
                <groupId>org.eclipse.californium</groupId>
                <artifactId>scandium</artifactId>
                <version>2.0.0-M7</version>
            </dependency>
    

    2.服务器端(提供接口)

        private void server() throws UnknownHostException {
            CoapServer coapServer = new CoapServer();
            //resource-name 资源名 对应controller的路径参数。路径为/resource-name
            //new ConcurrentCoapResource("resource-name", 5(线程池线程数)) 按需使用线程安全的resource
            coapServer.add(new CoAPResourceExample("resource-name"));
            //CoapEndpoint 是Coap协议的一个传输图层(图层堆栈,层层处理消息),位于 MessageDeliverer 和 Connector 之间。详细解释请看作者类描述,很详细
            CoapEndpoint.CoapEndpointBuilder coapEndpointBuilder = new CoapEndpoint.CoapEndpointBuilder();
            // CoapEndpoint除了传输还可设置端口以及内部有个线程池保证线程安全
            // 设置接口(Resource)绑定的ip地址 和端口
            coapEndpointBuilder.setInetSocketAddress(new InetSocketAddress(InetAddress.getByName("ip"), 5683));
            //or
            coapEndpointBuilder.setPort(5683);
            //网络配置参数,可自定义,这里使用默认配置
            coapEndpointBuilder.setNetworkConfig(NetworkConfig.getStandard());
            //可自定义连接池
            //coapEndpointBuilder.setConnector()
            coapServer.addEndpoint(coapEndpointBuilder.build());
            coapServer.start();
        }
    
        public static class CoAPResourceExample extends CoapResource {
            public CoAPResourceExample(String name) {
                //resource-name 资源名 对应controller的路径参数/uri
                super(name);
            }
    
            public void handleGET(CoapExchange exchange) {
                //获取路径参数
                List<String> queries = exchange.getRequestOptions().getUriQuery();
                //ResponseCode 响应码对应http状态码  contentFormat对应http的contentType。50 =》JSON  0 =》text
                exchange.respond(CoAP.ResponseCode.CONTENT, "hello world", 0);
            }
    
            public void handlePOST(CoapExchange exchange) {
                //发送给客户端消息已到达
                exchange.accept();
                //获取请求参数
                String requestBody = exchange.getRequestText();
                //ResponseCode 响应码对应http状态码  contentFormat对应http的contentType
                exchange.respond(CoAP.ResponseCode.CREATED, "{}", 50);
            }
    
            public void handlePUT(CoapExchange exchange) {
                // ...
                exchange.respond(CoAP.ResponseCode.CHANGED);
                changed(); //父类方法 notify all observers(client) the state has changed 见方法注释
            }
    
            public void handleDELETE(CoapExchange exchange) {
                delete();//父类方法 删除当前resource并通知所有observers(client)
                exchange.respond(CoAP.ResponseCode.DELETED);
            }
        }
    

    3.客户端(调用服务器端接口)

        private void client() throws URISyntaxException {
            URI uri = new URI("coap://ip/resource-name?type=1");// 请求服务器资源resource-name,注意默认端口为5683
            String body = "{\"body\":\"hello\"}";
            CoapClient client = new CoapClient(uri);
            CoapResponse response = client.post(body.getBytes(), 50);
            //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)); // 打印格式良好的输出
            }
        }
    

    作者:JINCLZJ

    物联沃分享整理
    物联沃-IOTWORD物联网 » CoAP协议入门解析(一)

    发表回复