当前位置: 首页 > 工具软件 > Californium > 使用案例 >

CoAP如何趟过californium 的坑: Caused by: java.lang.IllegalStateException: automatic message IDs exhausted

吕承福
2023-12-01

使用californium进行CoAP通信的时候,客户端发送速度过快的时候,有时候会出现连续4分钟(实际上是247秒)发不出数据的。

原因是,californium实现了一个UDP异步发送可靠性框架。根据CoAP协议,它每个请求需要等待服务端的响应返回。它在发送报文的时候,实际上是会把上次发送报文的时间,保存到内存表中,等到收到服务器的报文的时候,那么就会刷新这个时间。

那么下次发送报文的时候,它就根据这个内存表记录的时间,决定要不要真的发送数据。

如果默认的4分钟超时后,依然没有返回,那么就可以发送下一个数据了。

但是UDP报文是不可靠的,可能会有概率性丢失,那么这个时候,就会等待超时4分钟。

那么就会造成4分钟,虽然你不断调用CoapClient的发送接口,但实际上无法真实发送数据的问题。

4分钟啊,很多应用都是不可接受的。

// 问题代码
@Override
	public int getNextMessageId() {
		final long now = ClockUtil.nanoRealtime();
		synchronized (this) {
			// mask mid to the min-max range
			int mid = (currentMID & 0xffff) % range;
			int index = mid / sizeOfGroups;
			int nextIndex = (index + 1) % numberOfGroups;
            // 问题代码
			if ((midLease[nextIndex] - now) < 0) {
				midLease[index] = now + exchangeLifetimeNanos;
				currentMID = mid + 1;
				return mid + min;
			}
		}
		String time = TimeUnit.NANOSECONDS.toSeconds(exchangeLifetimeNanos) + "s";
		throw new IllegalStateException(
				"No MID available, all [" + min + "-" + (min + range) + ") MID-groups in use! (MID lifetime " + time + "!)");
	}

问题的补救措施。

在创建CoapClient对象的时候,调用下列代码,将生命周期设置为2000秒,那么这时候实际上时间窗口比较短,即使UDP丢包,也不会造成造成长时间等待

EndpointManager.getEndpointManager().getDefaultEndpoint(CoAP.COAP_URI_SCHEME).getConfig().set(CoapConfig.EXCHANGE_LIFETIME, 2000L, TimeUnit.MILLISECONDS);

范例测试代码

public static void hello() throws Exception {
        // 创建一个资源请求hello资源,注意默认端口为5683
        URI uri = new URI("localhost:5684/hello");
        CoapClient client = new CoapClient(uri);   
        
        // 关键代码:设置发送缓冲区的生命周期   
  EndpointManager.getEndpointManager().getDefaultEndpoint(CoAP.COAP_URI_SCHEME).getConfig().set(CoapConfig.EXCHANGE_LIFETIME, 2000L, TimeUnit.MILLISECONDS);

        CoapResponse response = null;
        for (int i = 0; i < 1000000; i++) {
            try {
                response = client.get();
                if (response == null) {
                    int x = 0;
                } else {
                    int x = 0;
                }
            } catch (IOException ioe) {
                if (ioe.getCause() instanceof IllegalStateException && "automatic message IDs exhausted".equals(ioe.getCause().getMessage())) {
                    //         Thread.sleep(100);
                }

            } catch (Exception e) {
                e.printStackTrace();
                continue;

            }
        }
 类似资料: