CoAP协议学习(附简单demo)

CoAP是什么

CoAP是受限制的应用协议(Constrained Application Protocol)的代名词。由于通常物联网设备都是资源限制型的,有限的CPU能力,有限RAM,有限的flash,有限的网络带宽, 针对此类特殊场景,COAP协议借鉴了HTTP协议机制并简化了协议包格式。 CoAP是一种应用层协议,它运行于UDP协议之上而不是像HTTP那样运行于TCP之上。CoAP协议非常小巧,最小的数据包仅为4字节。

COAP协议特点

  1. 基于消息模型,定义了4个消息类型,以消息为数据通信载体,通过交换网络消息来实现设备间数据通信对CoAP Server云端设备资源操作都是通过请求与响应机制来完成,类似HTTP,设备端可通过4个请求方法(GET, PUT, POST, DELETE)
  2. 对服务器端资源进行操作。 请求与响应的数据包都是放在CoAP消息里面进行传输的基于消息的双向通信(M2M),CoAP Client与CoAP server双方都可以独立向对方发送请求.双方可当client或者server角色。
  3. 协议包轻量级,最小长度仅为4B。
  4. 支持可靠传输,数据重传,块传输。 确保数据可靠到达。
  5. 支持IP多播, 即可以同时向多个设备发送请求(比如CoAP client搜索CoAP Server)
  6. 非长连接通信,适用于低功耗物联网场景

CoAP的URL

在HTTP的世界中,RESTFul协议由于其简单性和适用性,在WEB应用中越来越受欢迎,这样的道理同样适用于CoAP。一个CoAP资源可以被一个URI所描述,例如一个设备可以测量温度,那么这个温度传感器的URI被描述为:CoAP://machine.address:5683/sensors/temperature。请注意,CoAP的默认UDP端口号为5683。

CoAP的请求和响应

HTTP 与 COAP协议都是通过4个请求方法(GET, PUT, POST, DELETE)对服务器端资源进行操作。 两者之间明显的区别在于HTTP是通过文本描述方式描述协议包内容,协议包里面会包含一些空格符,换行符等,协议包可读性很强。而COAP是通过定义 二进制各位段功能来描述协议包内容。 因此COAP协议包大小更小,更紧凑。COAP协议最小的协议包只有4B。 协议包需要经过解析后才能知道里面具体内容,另还有一个明显的区别是传统的HTTP协议是主机与web服务器之间是单向通信的(用websocket除外)。而CoAP系统中CoAP Client与CoAP server是可以双向通信,双方都可以主动向对方发送请求。

CoAP消息类型

CoAP采用与HTTP协议相同的请求响应工作模式。CoAP协议共有4中不同的消息类型。 CON——需要被确认的请求,如果CON请求被发送,那么对方必须做出响应。 NON——不需要被确认的请求,如果NON请求被发送,那么对方不必做出回应。 ACK——应答消息,接受到CON消息的响应。 RST——复位消息,当接收者接受到的消息包含一个错误,接受者解析消息或者不再关心发送者发送的内容,那么复位消息将会被发送。

CoAP消息结构

一个CoAP消息最小为4个字节,以下是CoAP协议不同部分的描述。 【版本Version】:类似于IPv6和IPv6,仅仅是一个版本号。 【消息类型Message Type】:CON,NON,ACK,RST。 【消息ID Message ID】:每个CoAP消息都有一个ID,在一次会话中ID总是保持不变。但在这个会话之后该ID会被回收利用。 【标记 Token】:标记是ID的另一种表现。 【选项 Options】:CoAP选项类似于HTTP请求头,它包括CoAP消息本身,例如CoAP端口号,CoAP主机和CoAP查询字符串等。 【负载Payload】:真正有用的被交互的数据。

Java开发框架可以使用eclipse californium maven

导入依赖包

<!--CoAP依赖-->
<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>

服务端

public class CoAPServer {
    public static void main(String[] args) {
        new CoAPServer().startServer();
    }
    public void startServer(){
        CoapServer server = new CoapServer(5683);//主机为localhost 端口为默认端口5683
        server.add(new CommonHandler("car"));
        server.add(new CoapResource("hello"));
        server.start();
    }
    class CommonHandler extends CoapResource {
        public CommonHandler(String name) {
            super(name);
        }
        @Override
        public void handleGET(CoapExchange exchange) { //重写处理GET请求的方法
            System.out.println("收到Get请求,消息内容为:"+exchange.getRequestText());
            exchange.respond(CoAP.ResponseCode.CONTENT, "OK");
        }
        public void handlePOST(CoapExchange exchange) {
            System.out.println("收到Post请求,消息内容为:"+exchange.getRequestText());
            exchange.respond(CoAP.ResponseCode.CONTENT,"OK");
        }
        //下面还可以重写处理DELETE、UPDATE的方法
    }
}

客户端

public class CoAPClient {
    public static void main(String[] args) throws URISyntaxException {
        new CoAPClient().startListen();
    }
    public void startListen() throws URISyntaxException {
        new Thread(new SendMessageThread(new URI("localhost:5683/car"))).start();//创建一个资源请求hello资源,注意默认端口为5683
    }
    class SendMessageThread implements Runnable {
        URI uri;
        SendMessageThread(URI uri) throws URISyntaxException {
            this.uri = uri;
        }
        @Override
        public void run() {
            CoapClient client = new CoapClient(uri);
            /** 反复将输入发送到服务端 */
            while (true) {
                BufferedReader in = new BufferedReader(new InputStreamReader(System.in));// 包装控制台输入流
                try {
                    String msg = in.readLine();
                    CoapResponse response = client.post(msg, MediaTypeRegistry.TEXT_PLAIN);
                    if(response !=null){
                        System.out.println("Status Code: "+response.getCode());  //打印请求状态码
                        System.out.println("选项参数: "+response.getOptions());  //选项参数
                        System.out.println("文本内容: "+response.getResponseText());  //获取内容文本信息
                        System.out.println("\nAdvanced\n");    //
                        System.out.println(Utils.prettyPrint(response));  //打印格式良好的输出
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
 

ref.

https://en.wikipedia.org/wiki/Constrained_Application_Protocol

https://blog.csdn.net/xukai871105/article/details/17734163

https://github.com/eclipse/californium/

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据