> 文档中心 > Android中使用CoAP协议

Android中使用CoAP协议


什么是CoAP协议

CoAP(Constrained Application Protocol)协议是一种物联网协议。与传统的PC、智能手机相比,物联网设备大多是资源限制型的,有限的CPU、RAM、Flash、网络带宽等。对于这些设备来说,直接使用TCP和HTTP协议是不太现实的。

CoAP协议主要有以下特征

  • 受限制的小型设备的Web传输协议(类似于HTTP)
  • 异步信息交换
  • 低开销,非常易于解析
  • 支持URI和内容类型
  • 代理和缓存功能

从抽象协议层,CoAP可以表示为
在这里插入图片描述
如上所示,CoAP协议分为Request/Response和Messages层,其中,Messages层处理UDP和异步消息。Request/Response基于请求/响应消息来管理请求/响应交互

CoAP支持始终不同的消息类型

  • CON Confirmable 可确认的
  • NON Non-Confirmable 无法确认
  • Acknowledge 确认
  • Reset 重置

这里我们重点介绍下可确认消息与不可确认消息。

可确认消息是可靠消息,在两个端点之间交换信息时,这些消息可能是可靠的。在CoAP中,使用确认消息(CON)获得可靠的消息。使用这些消息,客户端可以确保消息将达到服务器。反复发送确认消息,知道另一方发送确认回复消息(ACK)。ACK消息包含与确认消息(CON)相同的ID。

整个过程如下图所示
在这里插入图片描述
不可确认消息(NON)是指不需要服务端来确认的消息。它们是不可靠消息,或者换句话说,这些消息不包含必须传递给服务器的关键信息。包含从传感器读取的值的消息属于此类别。

即使这些消息不可靠,它们也具有唯一的ID。

在这里插入图片描述
值的注意的是,与HTTP协议类似,CoAP协议的Request方法包含以下四种。

  • GET方法 用于获取某资源
  • POST方法 用于创建某资源
  • PUT方法 用于更新某资源
  • DELETE方法 用于删除某资源

当然,以上的Request方法都是官方的定义,具体的功能由代码来决定。POST也可以用来获取信息

下面来重点介绍下Android端如何集成使用CoAP服务。

集成

这里我们使用org.eclipse.californium:californium-core开源框架来实现CoAP功能
GitHub地址

https://github.com/eclipse/californium

项目的build.gradle文件集成如下代码

dependencies {    def californiumVersion = '3.2.0'    implementation 'org.eclipse.californium:californium-core:'+californiumVersion}

服务端实现

服务端开启CoAP服务时,需要开启一个Service,如下

class DemoServerService : Service() {    private lateinit var mCoapService: CoapServer    private lateinit var mBinder: Binder    override fun onCreate() { this.mCoapService = CoapServer(6723) //这里需要定义端口号 val coapResource = CoapResource("base") coapResource.add(AResource()) this.mCoapService.add(coapResource)    }    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { kotlin.runCatching {     this.mCoapService.start()     myLogger.d("onStartCommand") } return super.onStartCommand(intent, flags, startId)    }}

这里AResource的定义如下

class SearchResource : BaseCoapResource("a") {    private val myLogger: MyLogger by lazy { MyLogger.get(SearchResource::class.java.simpleName) }    override fun handleGET(exchange: CoapExchange?) { super.handleGET(exchange) exchange?.respond("this is get")    }    override fun handlePOST(exchange: CoapExchange?) { if (exchange == null) return myLogger.d("requestString:${exchange.requestText}")    }}

这样,当我们启动DemoServerService服务时,服务端就开启了一个CoAP服务,如下

val intent = Intent(context, DemoServerService::class.java)context.startService(intent)

客户端实现

客户端如何发起一个CoAP请求呢?示例代码如下,我们对服务端发起一个POST请求

   internal fun request() { val url = "coap://192.168.3.12:6723)}/base/a" val map = ArrayMap<String, Any>() map["deviceId"] = "1234" val handler = object : CoapHandler {     override fun onLoad(response: CoapResponse?) {  if (response == null) return  myLogger.d(Utils.prettyPrint(response))     }     override fun onError() {  myLogger.d("connect error")  callback?.invoke(false)     } } val coapClient = CoapClient(url).useNONs().setTimeout(UAMClientManager.DEFAULT_TIMEOUT) coapClient.post(handler, Gson().toJson(map), MediaTypeRegistry.APPLICATION_JSON)    }

实现广播

如何向局域网内发起一个广播呢?我们都知道只需要向网关发送CoAP请求即可。但是实践中,我们发现一个CoAP request只能收到一个response,那怎么能保证一个Request收到多个Response呢?

如下实现,我们将发起网络请求的时候,不使用默认的CoapClient,而是使用我们定义的MulticastCoapClient

class MulticastCoapClient(url: String) : CoapClient(url) {    companion object { private val TAG = MulticastCoapClient::class.java.simpleName    }    private val logger by lazy { MyLogger.get(TAG) }    override fun send(request: Request?): Request { if (request != null) {     val address = request.localAddress     request.setLocalAddress(address, true) } return super.send(request)    }}

如此,我们就可以实现局域网内广播CoAP请求了!