GithubHelp home page GithubHelp logo

wizzercn / mqttwk Goto Github PK

View Code? Open in Web Editor NEW
605.0 22.0 222.0 646 KB

Java + Netty 实现的高并发高可用MQTT服务broker,轻松支持10万并发(有群友实现了130万在线)

License: Apache License 2.0

Java 98.28% HTML 1.72%

mqttwk's Introduction


MqttWk - by netty

GitHub release License PowerByNutz

本项目开源免费,欢迎交流学习、贡献代码。

MqttWk

  • QQ群号:225991747

开发指南

技术体系

  1. 使用 netty 实现通信及协议解析
  2. 使用 nutzboot 提供依赖注入及属性配置
  3. 使用 redis 实现消息缓存,集群
  4. 使用 kafka 实现消息转发(可选)

项目结构

MqttWk
  ├── mqtt-auth -- MQTT服务连接时用户名和密码认证
  ├── mqtt-broker -- MQTT服务器功能的核心实现
  ├── mqtt-common -- 公共类及其他模块使用的服务接口及对象
  ├── mqtt-store -- MQTT服务器会话信息(redis缓存及kafka加载)
  ├── mqtt-client -- MQTT客户端示例代码(配置文件修改数据库连接启动之)
  ├── mqtt-zoo -- 教程文档或文件
    ├── mqtt-test-kafka -- kafka消费者接收消息
    ├── mqtt-test-websocket -- websocket通信测试示例

功能说明

  1. 参考MQTT3.1.1规范实现
  2. 完整的QoS服务质量等级实现
  3. 遗嘱消息, 保留消息及消息分发重试
  4. 心跳机制
  5. MQTT连接认证(可选择是否开启)
  6. SSL方式连接(可选择是否开启)
  7. 主题过滤(支持单主题订阅如 test_topic /mqtt/test --不能以/结尾, 通配符订阅 # /mqtt/# --以#结尾)
  8. Websocket支持(可选择是否开启)
  9. 集群功能(可选择是否开启)
  10. Kafka消息转发功能(可选择是否开启)
  11. 启动后查看统计数据 http://127.0.0.1:8922/open/api/mqttwk/info

快速开始

  • JDK1.8
  • 项目根目录执行 mvn install
  • mqtt-broker 下执行 mvn clean package nutzboot:shade 进行打包
  • 运行并加载jar内部yaml配置文件 java -jar mqtt-broker-xxx.jar -Dnutz.profiles.active=prod [此时加载application-prod.yaml配置文件]
  • 部署并加载指定文件夹下yaml配置文件 nohup java -Dnutz.boot.configure.yaml.dir=/data -jar mqtt-broker-xxx.jar >/dev/null 2>&1 &
  • 打开mqtt-spy客户端, 填写相应配置下载
  • 连接端口: 8885, websocket 端口: 9995 websocket
  • 连接使用的用户名: demo
  • 连接使用的密码: 8F3B8DE2FDC8BD3D792BE77EAC412010971765E5BDD6C499ADCEE840CE441BDEF17E30684BD95CA708F55022222CC6161D0D23C2DFCB12F8AC998F59E7213393
  • 连接使用的证书在 mqtt-zoo\keystore\server.cer

集群使用

  • 多机环境集群:
mqttwk:
  broker:
    cluster-on: true
    kafka:
      # 是否启用kafka消息转发
      broker-enabled: false
      bootstrap:
        servers: 192.168.1.101:9092,192.168.1.102:9093
redis:
  mode: cluster
  nodes: 192.168.1.103:16379,192.168.1.104:26379,192.168.1.103:36379
  • 单机环境集群:
mqttwk:
  broker:
    cluster-on: true
    kafka:
      # 是否启用kafka消息转发
      broker-enabled: false
      bootstrap:
        servers: 192.168.1.101:9092,192.168.1.102:9093
redis:
  mode: normal
  host: 127.0.0.1
  port: 6379

自定义 - 连接认证

  • 默认只是简单使用对用户名进行RSA密钥对加密生成密码, 连接认证时对密码进行解密和相应用户名进行匹配认证
  • 使用中如果需要实现连接数据库或其他方式进行连接认证, 只需要重写mqtt-auth模块下的相应方法即可

自定义 - 服务端证书

  • 服务端证书存储在mqtt-brokerresources/keystore/server.pfx
  • 用户可以制作自己的证书, 但存储位置和文件名必须使用上述描述的位置及文件名

生产环境部署

  • 多机环境集群
  • 负载均衡: 富人用 L4 Switch,穷人用 Linux HAProxy

示例截图

示例截图

参考项目

如果您觉得还不错请在右上角点一下 star,帮忙转发,谢谢 🙏🙏🙏 大家的支持是开源最大动力

mqttwk's People

Contributors

wendal avatar wizzercn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mqttwk's Issues

开启集群功能时会发送两条消息造成重复

开启集群后:
1)Publish -> processPublish -> internalCommunication.internalSend(internalMessage);
会广播一条消息,然后Broker各自收到消息判断是否在自己节点,然后下发消息。
Publish -> processPublish -> this.sendPublishMessage
正常发送消息。

如果Client1和Client2连接到同一个Broker,开启集群,Client1发送Client2订阅的主题,Client2除了集群收到一条,还会本地收到一条,产生两条信息造成重复。

解决:
InternalMessage增加BrokerId信息,判断是不是自己Broker
或者第二条send判断一下是否是集群模式,是就不发。

单例模式通配符订阅消息重复发送

================ mqttwk =============
【发布】/topic1/1/1
【订阅收到】
/topic1/+/1 :2条
/topic1/#:2条
================= moquette ============
【发布】/topic1/1/1
【订阅收到】
/topic1/+/1 :1条
/topic1/#:1条

代码不完整

[INFO] mqttwk 1.0-SNAPSHOT ................................ SUCCESS [ 0.284 s]
[INFO] wk-broker .......................................... FAILURE [ 6.043 s]
[INFO] wk-test ............................................ SKIPPED
[INFO] wk-test-device-client .............................. SKIPPED
[INFO] wk-test-server-client 1.0-SNAPSHOT ................. SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.064 s
[INFO] Finished at: 2018-07-03T15:52:29+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.3:compile (default-compile) on project wk-broker: Compilation failure: Compilation failure:
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[3,29] 找不到符号
[ERROR] 符号: 类 ConnectionDescriptor
[ERROR] 位置: 程序包 cn.wizzer.mqttwk.mqtt
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[4,29] 找不到符号
[ERROR] 符号: 类 ConnectionDescriptorStore
[ERROR] 位置: 程序包 cn.wizzer.mqttwk.mqtt
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[6,48] 找不到符号
[ERROR] 符号: 类 IConnectionsManager
[ERROR] 位置: 程序包 cn.wizzer.mqttwk.mqtt.common.connections
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[150,29] 找不到符号
[ERROR] 符号: 类 ConnectionDescriptor
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[108,9] 找不到符号
[ERROR] 符号: 类 ConnectionDescriptor
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[108,47] 找不到符号
[ERROR] 符号: 类 ConnectionDescriptor
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[109,15] 找不到符号
[ERROR] 符号: 类 ConnectionDescriptor
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[109,51] 找不到符号
[ERROR] 符号: 变量 connectionDescriptors
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[113,17] 找不到符号
[ERROR] 符号: 变量 connectionDescriptors
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[114,17] 找不到符号
[ERROR] 符号: 变量 connectionDescriptors
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[124,9] 找不到符号
[ERROR] 符号: 变量 m_interceptor
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[126,37] 找不到符号
[ERROR] 符号: 变量 SENDACK
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[126,46] 找不到符号
[ERROR] 符号: 变量 SESSION_CREATED
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[130,15] 找不到符号
[ERROR] 符号: 类 ClientSession
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[130,49] 找不到符号
[ERROR] 符号: 变量 sessionsRepository
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[138,26] 找不到符号
[ERROR] 符号: 变量 channel
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[140,56] 找不到符号
[ERROR] 符号: 变量 MESSAGES_REPUBLISHED
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[140,78] 找不到符号
[ERROR] 符号: 变量 ESTABLISHED
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[152,56] 找不到符号
[ERROR] 符号: 变量 DISCONNECTED
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[152,70] 找不到符号
[ERROR] 符号: 变量 SENDACK
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[158,9] 找不到符号
[ERROR] 符号: 类 ClientSession
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[158,43] 找不到符号
[ERROR] 符号: 变量 sessionsRepository
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[166,34] 找不到符号
[ERROR] 符号: 变量 mqttPacket
[ERROR] 位置: 类 cn.wizzer.mqttwk.mqtt.common.handler.MqttConnectHandler
[ERROR] /source/third/MqttWk/wk-broker/src/main/java/cn/wizzer/mqttwk/mqtt/common/handler/MqttConnectHandler.java:[171,21] 找不到符号
[ERROR] 符号: 变量 subscriptions
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn -rf :wk-broker

偶发的异常,未找到规律

[DEBUG] 23:16:04.577 cn.wizzer.iot.mqtt.server.broker.protocol.Publish.lambda$sendPublishMessage$0(Publish.java:129) - PUBLISH - clientId: e16e6243ffd2fae1eb9b4c606bdf8b90, topic: /airm2m/tracker/862285033462874/will, Qos: 1, messageId: 2
[WARN ] 23:16:04.578 io.netty.util.internal.logging.Slf4JLogger.warn(Slf4JLogger.java:151) - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.lang.IllegalArgumentException: messageId: 0 (expected: 1 ~ 65535)
        at io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader.from(MqttMessageIdVariableHeader.java:31)
        at cn.wizzer.iot.mqtt.server.broker.protocol.Publish.sendPubAckMessage(Publish.java:161)
        at cn.wizzer.iot.mqtt.server.broker.protocol.Publish.processPublish(Publish.java:80)
        at cn.wizzer.iot.mqtt.server.broker.handler.BrokerHandler.userEventTriggered(BrokerHandler.java:132)
        at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:329)
        at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:315)
        at io.netty.channel.AbstractChannelHandlerContext.fireUserEventTriggered(AbstractChannelHandlerContext.java:307)
        at io.netty.channel.ChannelInboundHandlerAdapter.userEventTriggered(ChannelInboundHandlerAdapter.java:108)
        at io.netty.handler.codec.ByteToMessageDecoder.userEventTriggered(ByteToMessageDecoder.java:353)
        at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:329)
        at io.netty.channel.AbstractChannelHandlerContext.invokeUserEventTriggered(AbstractChannelHandlerContext.java:315)
        at io.netty.channel.AbstractChannelHandlerContext.fireUserEventTriggered(AbstractChannelHandlerContext.java:307)
        at io.netty.handler.timeout.IdleStateHandler.channelIdle(IdleStateHandler.java:371)
        at io.netty.handler.timeout.IdleStateHandler$AllIdleTimeoutTask.run(IdleStateHandler.java:567)
        at io.netty.handler.timeout.IdleStateHandler$AbstractIdleTask.run(IdleStateHandler.java:466)
        at io.netty.util.concurrent.PromiseTask$RunnableAdapter.call(PromiseTask.java:38)
        at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:127)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
        at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:322)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:745)

在使用org.eclipse.paho.client.mqttv3进行qos1级别消息发送时,接收客户端会出现由于会话过期而导致的链接断开

原因:在mqttv3客户端源码中,org.eclipse.paho.client.mqttv3.internal.ClientState#checkForActivity这个方法中会判断是否需要发送心跳。 其中有个变量lastInboundActivity会随着puback的发送而改变。这个变量会推迟心跳发送的时机。从而导致一个只接受消息而不发送消息的客户端在下次发送心跳的时间间隔会超过你设定的keepAlive*1.5的大小

建议在PubAck处理方法中添加对session的过期时间处理

启动报错是什么原因

Plugin org.apache.maven.plugins:maven-install-plugin:2.4 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-install-plugin:jar:2.4: 1 problem was encountered while building the effective model
[ERROR] [FATAL] Non-parseable POM D:\01_java_tools\repository\org\apache\maven\plugins\maven-install-plugin\2.4\maven-install-plugin-2.4.pom: unexpected character in markup (position: START_TAG seen ... function init() {\n loaded += 1;\n\n if (loaded < ... @44:24) @ line 44, column 24
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginResolutionException

java.lang.NullPointerException报错

线上连接700台设备左右,频繁报空指针错误。有两个地方:
1、cn.wizzer.iot.mqtt.server.broker.protocol.DisConnect

    public void processDisConnect(Channel channel, MqttMessage msg) {
        String clientId = (String) channel.attr(AttributeKey.valueOf("clientId")).get();
        SessionStore sessionStore = sessionStoreService.get(clientId);
       // BUG:在极端条件下,redis中保存的session信息过期,导致sessionStore=null,此处报NullPointerException。
       // 判断条件修改为sessionStore != null && sessionStore.isCleanSession()
        if (sessionStore.isCleanSession()) {

        }
       // ...省略部分代码
    }

2、cn.wizzer.iot.mqtt.server.broker.handler.BrokerHandler

@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
       // ...省略部分代码
	// 发送遗嘱消息
	if (this.protocolProcess.getSessionStoreService().containsKey(clientId)) {
	    SessionStore sessionStore = this.protocolProcess.getSessionStoreService().get(clientId);
	    // BUG:IdleStateHandler检测间隔与redis超时时间相同。极端条件下,containsKey=true,但是get返回null。
            // 判断条件修改为:null != sessionStore && sessionStore.getWillMessage() != null
            // 或者考虑仅使用this.protocolProcess.getSessionStoreService().get(clientId),然后判断null即可
	    if (sessionStore.getWillMessage() != null) {
	        this.protocolProcess.publish().processPublish(ctx.channel(), sessionStore.getWillMessage());
	    }
      // ...省略部分代码
    }

另外,BrokerHandler.exceptionCaught()方法最好能将异常信息打印出来,方便从日志中查看异常详细。以上问题就是加了打印才发现了具体的代码,如果不加仅打印了Exception的message:

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (cause instanceof IOException) {
            // 远程主机强迫关闭了一个现有的连接的异常
            ctx.close();
        } else {
            // FIX:打印异常信息
            logger.error("出现了异常", cause);
            super.exceptionCaught(ctx, cause);
        }
    }

多机集群功能支持吗?

集群功能有实现吗?对于集群中三台机器A、B、C,现在:
设备d1连接机器A并订阅topic:/a/+/c,
设备d2连接机器B并订阅topic:/a/b/#,
设备d3连接机器C并pub消息到topic:/a/b/c,设备d1、设备d2能收到消息吗?

看源码pub消息时只是在本机取出了符合条件的订阅topic,从而找出对应的session,再找出对应的channel进行下发,但不在本机的会话就不能下发了。

关于集群的几个问题

  1. 集群是主从模式的还是无中心化(decentralized)集群呢?
  2. 客户端session会在集群间复制吗?
    假设有三个n1,n2,n2,客户端c1。
    c1先连接n1节点(clean_session=false),然后断开连接,再连接n2节点,n2节点是否能够恢复该session?
  3. 如果两个相同clientId的客户端c1,c2。同时连接两个节点n1,n2。集群会保证踢掉其中一个客户端吗?
  4. 如果集群出现网络分区的问题,节点间如何恢复?
  5. 如果集群节点crash,有可能导致消息丢失吗?

谢谢

你好,感谢。

我使用你的mqtt broker 代码,自己修改下,集群功能自己重新开发。

目前已上正式产线,集群3台,接入设备超20w,稳定运行半年多,目前非常稳定。

非常感谢。

这个channelIdMap并不是并发安全的吧

@IocBean
@ChannelHandler.Sharable
public class BrokerHandler extends SimpleChannelInboundHandler<MqttMessage> {
@Inject
private ProtocolProcess protocolProcess;
@Inject
private BrokerProperties brokerProperties;
@Inject
private ChannelGroup channelGroup;
@Inject
private Map<String, ChannelId> channelIdMap;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
this.channelGroup.add(ctx.channel());
this.channelIdMap.put(brokerProperties.getId() + "_" + ctx.channel().id().asLongText(), ctx.channel().id());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
this.channelGroup.remove(ctx.channel());
this.channelIdMap.remove(brokerProperties.getId() + "_" + ctx.channel().id().asLongText());
}

web客户端

大神好,MqttWk 没有web端的管理平台么?我看wiki里是下载mqtt-spy。

请问是否,要在publish或其他操作的时候,同步redis的过期时间?

你好,向你请教一个问题:心跳
目前你是session信息存储到redis,
登录的时候,keepalive设置的是allIdleTime, channel.pipeline().addFirst("idle", new IdleStateHandler(0, 0, expire));
设备每次ping的时候, 延长redis的key失效时间。sessionStoreService.expire(clientId, sessionStore.getExpire());

假如:设备的那次心跳,服务器没有收到,redis的session缓存就会过期,消失。但是期间设备一直有publish操作,则userEventTriggered的idle事件不会触发。导致设备实际在线,在上层应用看来(从redis判断),则是一致离线。

请问是否,要再publish或其他操作的时候,同步redis的过期时间?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.