ThingsBoard-MQTT

前言

本篇从MQTT入手,研究相关源码
通过之前对代码结构的浏览,我们了解到MQTT的实现位于common/transport/mqtt模块
在这里插入图片描述
接下来以org.thingsboard.server.transport.mqtt.MqttTransportService为入口开始阅读

MqttTransportService

类注解

@Service("MqttTransportService")
@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.mqtt.enabled}'=='true')")

@Service实例化当前类并注册为MqttTransportService
@ConditionalOnExpression定义了启用条件

初始化方法

@PostConstruct
public void init() throws Exception {
	log.info("Setting resource leak detector level to {}", leakDetectorLevel);
	ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.valueOf(leakDetectorLevel.toUpperCase()));

	log.info("Starting MQTT transport...");
	bossGroup = new NioEventLoopGroup(bossGroupThreadCount);
	workerGroup = new NioEventLoopGroup(workerGroupThreadCount);
	ServerBootstrap b = new ServerBootstrap();
	b.group(bossGroup, workerGroup)
			.channel(NioServerSocketChannel.class)
			.childHandler(new MqttTransportServerInitializer(context, false))
			.childOption(ChannelOption.SO_KEEPALIVE, keepAlive);

	serverChannel = b.bind(host, port).sync().channel();
	if (sslEnabled) {
		b = new ServerBootstrap();
		b.group(bossGroup, workerGroup)
				.channel(NioServerSocketChannel.class)
				.childHandler(new MqttTransportServerInitializer(context, true))
				.childOption(ChannelOption.SO_KEEPALIVE, keepAlive);
		sslServerChannel = b.bind(sslHost, sslPort).sync().channel();
	}
	log.info("Mqtt transport started!");
}

熟悉Netty的话从即可看出MQTT服务正是基于Netty实现的

关键代码

.childHandler(new MqttTransportServerInitializer(context, false))

可知处理器为org.thingsboard.server.transport.mqtt.MqttTransportServerInitializer
构造参数context为传输上下文org.thingsboard.server.transport.mqtt.MqttTransportContext

@Autowired
private MqttTransportContext context;

MqttTransportContext

类注解

@Component
@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.mqtt.enabled}'=='true')")

关键属性

@Getter
@Autowired(required = false)
private MqttSslHandlerProvider sslHandlerProvider;

SSL处理器提供者

@Getter
@Autowired
private JsonMqttAdaptor jsonMqttAdaptor;

JSON格式的适配器org.thingsboard.server.transport.mqtt.adaptors.JsonMqttAdaptor

@Getter
@Autowired
private ProtoMqttAdaptor protoMqttAdaptor;

Proto格式的适配器org.thingsboard.server.transport.mqtt.adaptors.ProtoMqttAdaptor

接着阅读处理器代码

MqttTransportServerInitializer

继承自io.netty.channel.ChannelInitializer

初始化通道方法

//org.thingsboard.server.transport.mqtt.MqttTransportServerInitializer

@Override
public void initChannel(SocketChannel ch) {
	ChannelPipeline pipeline = ch.pipeline();
	SslHandler sslHandler = null;
	if (context.isProxyEnabled()) {
		pipeline.addLast("proxy", new HAProxyMessageDecoder());
		pipeline.addLast("ipFilter", new ProxyIpFilter(context));
	} else {
		pipeline.addLast("ipFilter", new IpFilter(context));
	}
	if (sslEnabled && context.getSslHandlerProvider() != null) {
		sslHandler = context.getSslHandlerProvider().getSslHandler();
		pipeline.addLast(sslHandler);
	}
	pipeline.addLast("decoder", new MqttDecoder(context.getMaxPayloadSize()));
	pipeline.addLast("encoder", MqttEncoder.INSTANCE);

	MqttTransportHandler handler = new MqttTransportHandler(context, sslHandler);

	pipeline.addLast(handler);
	ch.closeFuture().addListener(handler);
}

关键代码

pipeline.addLast("decoder", new MqttDecoder(context.getMaxPayloadSize()));

解码器,解析数据包,为实现MQTT协议的关键,由Netty提供

pipeline.addLast("encoder", MqttEncoder.INSTANCE);

编码器,构建数据包,为实现MQTT协议的关键,由Netty提供

MqttTransportHandler handler = new MqttTransportHandler(context, sslHandler);

pipeline.addLast(handler);

消息处理器org.thingsboard.server.transport.mqtt.MqttTransportHandler
此为MQTT消息处理的核心类

MqttTransportHandler

读取通道数据

//org.thingsboard.server.transport.mqtt.MqttTransportHandler

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
	log.trace("[{}] Processing msg: {}", sessionId, msg);
	if (address == null) {
		address = getAddress(ctx);
	}
	try {
		if (msg instanceof MqttMessage) {
			MqttMessage message = (MqttMessage) msg;
			if (message.decoderResult().isSuccess()) {
				processMqttMsg(ctx, message);
			} else {
				log.error("[{}] Message decoding failed: {}", sessionId, message.decoderResult().cause().getMessage());
				ctx.close();
			}
		} else {
			log.debug("[{}] Received non mqtt message: {}", sessionId, msg.getClass().getSimpleName());
			ctx.close();
		}
	} finally {
		ReferenceCountUtil.safeRelease(msg);
	}
}

关键方法

处理消息

processMqttMsg(ctx, message);
//org.thingsboard.server.transport.mqtt.MqttTransportHandler

void processMqttMsg(ChannelHandlerContext ctx, MqttMessage msg) {
	if (msg.fixedHeader() == null) {
		log.info("[{}:{}] Invalid message received", address.getHostName(), address.getPort());
		ctx.close();
		return;
	}
	deviceSessionCtx.setChannel(ctx);
	if (CONNECT.equals(msg.fixedHeader().messageType())) {
		processConnect(ctx, (MqttConnectMessage) msg);
	} else if (deviceSessionCtx.isProvisionOnly()) {
		processProvisionSessionMsg(ctx, msg);
	} else {
		enqueueRegularSessionMsg(ctx, msg);
	}
}
处理连接消息
processConnect(ctx, (MqttConnectMessage) msg);
//org.thingsboard.server.transport.mqtt.MqttTransportHandler

void processConnect(ChannelHandlerContext ctx, MqttConnectMessage msg) {
	log.debug("[{}][{}] Processing connect msg for client: {}!", address, sessionId, msg.payload().clientIdentifier());
	String userName = msg.payload().userName();
	String clientId = msg.payload().clientIdentifier();
	if (DataConstants.PROVISION.equals(userName) || DataConstants.PROVISION.equals(clientId)) {
		deviceSessionCtx.setProvisionOnly(true);
		ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, msg));
	} else {
		X509Certificate cert;
		if (sslHandler != null && (cert = getX509Certificate()) != null) {
			processX509CertConnect(ctx, cert, msg);
		} else {
			processAuthTokenConnect(ctx, msg);
		}
	}
}

由代码可知处理逻辑。若为预配置(用户名或客户端id为provision),则标记设备会话上下文并返回响应消息;否则根据是否启用SSL执行对应的处理
我们以Token验证方式继续探究

//org.thingsboard.server.transport.mqtt.MqttTransportHandler

private void processAuthTokenConnect(ChannelHandlerContext ctx, MqttConnectMessage connectMessage) {
	String userName = connectMessage.payload().userName();
	log.debug("[{}][{}] Processing connect msg for client with user name: {}!", address, sessionId, userName);
	TransportProtos.ValidateBasicMqttCredRequestMsg.Builder request = TransportProtos.ValidateBasicMqttCredRequestMsg.newBuilder()
			.setClientId(connectMessage.payload().clientIdentifier());
	if (userName != null) {
		request.setUserName(userName);
	}
	byte[] passwordBytes = connectMessage.payload().passwordInBytes();
	if (passwordBytes != null) {
		String password = new String(passwordBytes, CharsetUtil.UTF_8);
		request.setPassword(password);
	}
	transportService.process(DeviceTransportType.MQTT, request.build(),
			new TransportServiceCallback<>() {
				@Override
				public void onSuccess(ValidateDeviceCredentialsResponse msg) {
					onValidateDeviceResponse(msg, ctx, connectMessage);
				}

				@Override
				public void onError(Throwable e) {
					log.trace("[{}] Failed to process credentials: {}", address, userName, e);
					ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage));
					ctx.close();
				}
			});
}

这里提一下如下代码

TransportProtos.ValidateBasicMqttCredRequestMsg.Builder request = TransportProtos.ValidateBasicMqttCredRequestMsg.newBuilder()
		.setClientId(connectMessage.payload().clientIdentifier());

此处TransportProtosProtobuf定义,TransportProtos.ValidateBasicMqttCredRequestMsg.BuilderTransportProtos.ValidateBasicMqttCredRequestMsg.newBuilder()方法均为自动生成

syntax = "proto3";

package transport;

option java_package = "org.thingsboard.server.gen.transport";
option java_outer_classname = "TransportProtos";

message ValidateBasicMqttCredRequestMsg {
   string clientId = 1;
   string userName = 2;
   string password = 3;
}

先使用newBuilder()方法创建构造器,然后调用相关属性的set方法赋值,最后通过build()方法构造实例
接着调用transportService.process方法处理鉴权请求

DefaultTransportService

//org.thingsboard.server.common.transport.service.DefaultTransportService

@Override
public void process(DeviceTransportType transportType, TransportProtos.ValidateBasicMqttCredRequestMsg msg,
					TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
	log.trace("Processing msg: {}", msg);
	TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(),
			TransportApiRequestMsg.newBuilder().setValidateBasicMqttCredRequestMsg(msg).build());
	doProcess(transportType, protoMsg, callback);
}

封装验证请求,调用doProcess方法

//org.thingsboard.server.common.transport.service.DefaultTransportService

private void doProcess(DeviceTransportType transportType, TbProtoQueueMsg<TransportApiRequestMsg> protoMsg,
						TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
	ListenableFuture<ValidateDeviceCredentialsResponse> response = Futures.transform(transportApiRequestTemplate.send(protoMsg), tmp -> {
		TransportProtos.ValidateDeviceCredentialsResponseMsg msg = tmp.getValue().getValidateCredResponseMsg();
		ValidateDeviceCredentialsResponse.ValidateDeviceCredentialsResponseBuilder result = ValidateDeviceCredentialsResponse.builder();
		if (msg.hasDeviceInfo()) {
			result.credentials(msg.getCredentialsBody());
			TransportDeviceInfo tdi = getTransportDeviceInfo(msg.getDeviceInfo());
			result.deviceInfo(tdi);
			ByteString profileBody = msg.getProfileBody();
			if (!profileBody.isEmpty()) {
				DeviceProfile profile = deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody);
				if (transportType != DeviceTransportType.DEFAULT
						&& profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) {
					log.debug("[{}] Device profile [{}] has different transport type: {}, expected: {}", tdi.getDeviceId(), tdi.getDeviceProfileId(), profile.getTransportType(), transportType);
					throw new IllegalStateException("Device profile has different transport type: " + profile.getTransportType() + ". Expected: " + transportType);
				}
				result.deviceProfile(profile);
			}
		}
		return result.build();
	}, MoreExecutors.directExecutor());
	AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor);
}

方法内容看起来很多,其实也就两步
首先通过Futures.transform方法根据transportApiRequestTemplate.send(protoMsg)的返回结果,转换为org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse,写入设备信息
接着设置回调方法

AsyncCallbackTemplate

//org.thingsboard.server.queue.common.AsyncCallbackTemplate

public static <T> void withCallback(ListenableFuture<T> future, Consumer<T> onSuccess,
									Consumer<Throwable> onFailure, Executor executor) {
	FutureCallback<T> callback = new FutureCallback<T>() {
		@Override
		public void onSuccess(T result) {
			try {
				onSuccess.accept(result);
			} catch (Throwable th) {
				onFailure(th);
			}
		}

		@Override
		public void onFailure(Throwable t) {
			onFailure.accept(t);
		}
	};
	if (executor != null) {
		Futures.addCallback(future, callback, executor);
	} else {
		Futures.addCallback(future, callback, MoreExecutors.directExecutor());
	}
}

使用Futures.addCallback方法设置回调方法

现在,我们回头看成功和失败的回调方法,它位于MqttTransportHandlerprocessAuthTokenConnect方法中

处理认证成功回调

@Override
public void onSuccess(ValidateDeviceCredentialsResponse msg) {
	onValidateDeviceResponse(msg, ctx, connectMessage);
}

成功则调用onValidateDeviceResponse方法

//org.thingsboard.server.transport.mqtt.MqttTransportHandler

private void onValidateDeviceResponse(ValidateDeviceCredentialsResponse msg, ChannelHandlerContext ctx, MqttConnectMessage connectMessage) {
	if (!msg.hasDeviceInfo()) {
		context.onAuthFailure(address);
		ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, connectMessage));
		ctx.close();
	} else {
		context.onAuthSuccess(address);
		deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo());
		deviceSessionCtx.setDeviceProfile(msg.getDeviceProfile());
		deviceSessionCtx.setSessionInfo(SessionInfoCreator.create(msg, context, sessionId));
		transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_OPEN, new TransportServiceCallback<Void>() {
			@Override
			public void onSuccess(Void msg) {
				SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), MqttTransportHandler.this);
				checkGatewaySession(sessionMetaData);
				ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, connectMessage));
				deviceSessionCtx.setConnected(true);
				log.debug("[{}] Client connected!", sessionId);
				transportService.getCallbackExecutor().execute(() -> processMsgQueue(ctx)); //this callback will execute in Producer worker thread and hard or blocking work have to be submitted to the separate thread.
			}

			@Override
			public void onError(Throwable e) {
				if (e instanceof TbRateLimitsException) {
					log.trace("[{}] Failed to submit session event: {}", sessionId, e.getMessage());
				} else {
					log.warn("[{}] Failed to submit session event", sessionId, e);
				}
				ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage));
				ctx.close();
			}
		});
	}
}

若响应消息中不包含设备信息,则认证失败,直接返回认证失败
先向设备会话上下文中写入相关信息,之后调用transportService.process处理会话开启事件

DefaultTransportService

//org.thingsboard.server.common.transport.service.DefaultTransportService

@Override
public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.SessionEventMsg msg, TransportServiceCallback<Void> callback) {
	if (checkLimits(sessionInfo, msg, callback)) {
		reportActivityInternal(sessionInfo);
		sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo)
				.setSessionEvent(msg).build(), callback);
	}
}

checkLimits方法用于检查传输的速率限制,有兴趣自行了解
reportActivityInternal方法用户更新活动时间,有兴趣自行了解
调用sendToDeviceActor方法发送会话消息

//org.thingsboard.server.common.transport.service.DefaultTransportService

protected void sendToDeviceActor(TransportProtos.SessionInfoProto sessionInfo, TransportToDeviceActorMsg toDeviceActorMsg, TransportServiceCallback<Void> callback) {
	TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, getTenantId(sessionInfo), getDeviceId(sessionInfo));
	if (log.isTraceEnabled()) {
		log.trace("[{}][{}] Pushing to topic {} message {}", getTenantId(sessionInfo), getDeviceId(sessionInfo), tpi.getFullTopicName(), toDeviceActorMsg);
	}
	TransportTbQueueCallback transportTbQueueCallback = callback != null ?
			new TransportTbQueueCallback(callback) : null;
	tbCoreProducerStats.incrementTotal();
	StatsCallback wrappedCallback = new StatsCallback(transportTbQueueCallback, tbCoreProducerStats);
	tbCoreMsgProducer.send(tpi,
			new TbProtoQueueMsg<>(getRoutingKey(sessionInfo), 
					ToCoreMsg.newBuilder().setToDeviceActorMsg(toDeviceActorMsg).build()), 
			wrappedCallback);
}

封装回调对象,向核心模块发送消息
最后,回看一下回调处理,位于MqttTransportHandleronValidateDeviceResponse的方法中

处理会话成功回调

@Override
public void onSuccess(Void msg) {
	SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), MqttTransportHandler.this);
	checkGatewaySession(sessionMetaData);
	ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, connectMessage));
	deviceSessionCtx.setConnected(true);
	log.debug("[{}] Client connected!", sessionId);
	transportService.getCallbackExecutor().execute(() -> processMsgQueue(ctx)); //this callback will execute in Producer worker thread and hard or blocking work have to be submitted to the separate thread.
}

registerAsyncSession用于记录会话,有兴趣自行了解
checkGatewaySession用于检查是否为网关会话(重写活动时间),有兴趣自行了解
接着返回连接成功的消息
由于认证处理是异步的,故将收到的数据包先保存在队列中,认证成功后调用processMsgQueue方法处理队列中的消息
关于processMsgQueue方法后面再看

处理会话错误回调

@Override
public void onError(Throwable e) {
	if (e instanceof TbRateLimitsException) {
		log.trace("[{}] Failed to submit session event: {}", sessionId, e.getMessage());
	} else {
		log.warn("[{}] Failed to submit session event", sessionId, e);
	}

	ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage));
	ctx.close();
}

返回服务不可用

处理认证错误回调

@Override
public void onError(Throwable e) {
	log.trace("[{}] Failed to process credentials: {}", address, userName, e);
	ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage));
	ctx.close();
}

返回服务不可用
至此,连接消息的处理逻辑已基本清楚

处理预配置消息
processProvisionSessionMsg(ctx, msg);

用于使用指定的设备配置创建设备

//org.thingsboard.server.transport.mqtt.MqttTransportHandler

private void processProvisionSessionMsg(ChannelHandlerContext ctx, MqttMessage msg) {
	switch (msg.fixedHeader().messageType()) {
		case PUBLISH:
			MqttPublishMessage mqttMsg = (MqttPublishMessage) msg;
			String topicName = mqttMsg.variableHeader().topicName();
			int msgId = mqttMsg.variableHeader().packetId();
			try {
				if (topicName.equals(MqttTopics.DEVICE_PROVISION_REQUEST_TOPIC)) {
					try {
						TransportProtos.ProvisionDeviceRequestMsg provisionRequestMsg = deviceSessionCtx.getContext().getJsonMqttAdaptor().convertToProvisionRequestMsg(deviceSessionCtx, mqttMsg);
						transportService.process(provisionRequestMsg, new DeviceProvisionCallback(ctx, msgId, provisionRequestMsg));
						log.trace("[{}][{}] Processing provision publish msg [{}][{}]!", sessionId, deviceSessionCtx.getDeviceId(), topicName, msgId);
					} catch (Exception e) {
						if (e instanceof JsonParseException || (e.getCause() != null && e.getCause() instanceof JsonParseException)) {
							TransportProtos.ProvisionDeviceRequestMsg provisionRequestMsg = deviceSessionCtx.getContext().getProtoMqttAdaptor().convertToProvisionRequestMsg(deviceSessionCtx, mqttMsg);
							transportService.process(provisionRequestMsg, new DeviceProvisionCallback(ctx, msgId, provisionRequestMsg));
							deviceSessionCtx.setProvisionPayloadType(TransportPayloadType.PROTOBUF);
							log.trace("[{}][{}] Processing provision publish msg [{}][{}]!", sessionId, deviceSessionCtx.getDeviceId(), topicName, msgId);
						} else {
							throw e;
						}
					}
				} else {
					log.debug("[{}] Unsupported topic for provisioning requests: {}!", sessionId, topicName);
					ctx.close();
				}
			} catch (RuntimeException e) {
				log.warn("[{}] Failed to process publish msg [{}][{}]", sessionId, topicName, msgId, e);
				ctx.close();
			} catch (AdaptorException e) {
				log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, topicName, msgId, e);
				ctx.close();
			}
			break;
		case PINGREQ:
			ctx.writeAndFlush(new MqttMessage(new MqttFixedHeader(PINGRESP, false, AT_MOST_ONCE, false, 0)));
			break;
		case DISCONNECT:
			ctx.close();
			break;
	}
}

仅处理发布至 /provision/request 主题的消息,先尝试以JSON格式化数据,若数据不是JSON格式,则以ProtoBuf格式化数据
调用process方法处理请求,有兴趣自行了解

常规消息的入队
enqueueRegularSessionMsg(ctx, msg);
//org.thingsboard.server.transport.mqtt.MqttTransportHandler

void enqueueRegularSessionMsg(ChannelHandlerContext ctx, MqttMessage msg) {
	final int queueSize = deviceSessionCtx.getMsgQueueSize();
	if (queueSize >= context.getMessageQueueSizePerDeviceLimit()) {
		log.info("Closing current session because msq queue size for device {} exceed limit {} with msgQueueSize counter {} and actual queue size {}",
				deviceSessionCtx.getDeviceId(), context.getMessageQueueSizePerDeviceLimit(), queueSize, deviceSessionCtx.getMsgQueueSize());
		ctx.close();
		return;
	}

	deviceSessionCtx.addToQueue(msg);
	processMsgQueue(ctx); //Under the normal conditions the msg queue will contain 0 messages. Many messages will be processed on device connect event in separate thread pool
}

检查队列长度是未超限后,将消息添加至队列,然后调用processMsgQueue方法进行处理

//org.thingsboard.server.common.transport.service.DefaultTransportService

void processMsgQueue(ChannelHandlerContext ctx) {
	if (!deviceSessionCtx.isConnected()) {
		log.trace("[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}", sessionId, deviceSessionCtx.getDeviceId(), deviceSessionCtx.getMsgQueueSize());
		return;
	}
	deviceSessionCtx.tryProcessQueuedMsgs(msg -> processRegularSessionMsg(ctx, msg));
}

判断设备连接后调用org.thingsboard.server.transport.mqtt.session.DeviceSessionCtxtryProcessQueuedMsgs方法处理队列消息

DeviceSessionCtx

//org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx

public void tryProcessQueuedMsgs(Consumer<MqttMessage> msgProcessor) {
	while (!msgQueue.isEmpty()) {
		if (msgQueueProcessorLock.tryLock()) {
			try {
				MqttMessage msg;
				while ((msg = msgQueue.poll()) != null) {
					try {
						msgQueueSize.decrementAndGet();
						msgProcessor.accept(msg);
					} finally {
						ReferenceCountUtil.safeRelease(msg);
					}
				}
			} finally {
				msgQueueProcessorLock.unlock();
			}
		} else {
			return;
		}
	}
}

加锁保证了消息的顺序执行
接着看msgProcessor.accept(msg),即上文msg -> processRegularSessionMsg(ctx, msg)

//org.thingsboard.server.transport.mqtt.MqttTransportHandler

void processRegularSessionMsg(ChannelHandlerContext ctx, MqttMessage msg) {
	switch (msg.fixedHeader().messageType()) {
		case PUBLISH:
			processPublish(ctx, (MqttPublishMessage) msg);
			break;
		case SUBSCRIBE:
			processSubscribe(ctx, (MqttSubscribeMessage) msg);
			break;
		case UNSUBSCRIBE:
			processUnsubscribe(ctx, (MqttUnsubscribeMessage) msg);
			break;
		case PINGREQ:
			if (checkConnected(ctx, msg)) {
				ctx.writeAndFlush(new MqttMessage(new MqttFixedHeader(PINGRESP, false, AT_MOST_ONCE, false, 0)));
				transportService.reportActivity(deviceSessionCtx.getSessionInfo());
			}
			break;
		case DISCONNECT:
			ctx.close();
			break;
		case PUBACK:
			int msgId = ((MqttPubAckMessage) msg).variableHeader().messageId();
			TransportProtos.ToDeviceRpcRequestMsg rpcRequest = rpcAwaitingAck.remove(msgId);
			if (rpcRequest != null) {
				transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
			}
			break;
		default:
			break;
	}
}

根据消息类型进行后续的处理

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值