Commit d5910fe69cdfeb96a5a2bb7c85bbf8ee4bf027c3

Authored by xp.Huang
1 parent 85b24ea0

refactor: TCP/UDP结构调整及优化


(cherry picked from commit 69ed52a8427e1c7f2e1b0250693f796710c4999c)
1 1 /**
2 2 * Copyright © 2016-2022 The Thingsboard Authors
3 3 *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
  4 + * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
  5 + * except in compliance with the License. You may obtain a copy of the License at
7 6 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  7 + * <p>http://www.apache.org/licenses/LICENSE-2.0
9 8 *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
  9 + * <p>Unless required by applicable law or agreed to in writing, software distributed under the
  10 + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  11 + * express or implied. See the License for the specific language governing permissions and
14 12 * limitations under the License.
15 13 */
16 14 package org.thingsboard.server.transport.tcp;
17   -
18   -import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED;
19   -import static io.netty.handler.codec.mqtt.MqttMessageType.PUBACK;
20   -import static io.netty.handler.codec.mqtt.MqttMessageType.SUBACK;
21   -import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;
22   -import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED;
23   -import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN;
24   -
25   -import com.fasterxml.jackson.databind.JsonNode;
26   -import com.fasterxml.jackson.databind.node.ObjectNode;
27   -import com.fasterxml.jackson.databind.node.TextNode;
28   -import com.google.common.util.concurrent.FutureCallback;
29   -import com.google.common.util.concurrent.Futures;
30   -import com.google.common.util.concurrent.ListenableFuture;
31   -import com.google.common.util.concurrent.MoreExecutors;
32 15 import io.netty.buffer.ByteBuf;
33   -import io.netty.buffer.Unpooled;
34   -import io.netty.channel.ChannelFuture;
35 16 import io.netty.channel.ChannelHandlerContext;
36 17 import io.netty.channel.ChannelInboundHandlerAdapter;
37   -import io.netty.handler.codec.mqtt.*;
38   -import io.netty.handler.ssl.SslHandler;
39 18 import io.netty.util.ReferenceCountUtil;
40   -import io.netty.util.concurrent.Future;
41   -import io.netty.util.concurrent.GenericFutureListener;
42   -import java.io.IOException;
43 19 import java.net.InetSocketAddress;
44 20 import java.util.*;
45   -import java.util.concurrent.atomic.AtomicInteger;
46 21
  22 +import io.netty.util.concurrent.Future;
  23 +import io.netty.util.concurrent.GenericFutureListener;
47 24 import lombok.extern.slf4j.Slf4j;
48   -import org.apache.commons.lang3.StringUtils;
49   -import org.checkerframework.checker.nullness.qual.Nullable;
50   -import org.thingsboard.common.util.JacksonUtil;
51   -import org.thingsboard.server.common.data.DataConstants;
52   -import org.thingsboard.server.common.data.Device;
53   -import org.thingsboard.server.common.data.DeviceProfile;
54   -import org.thingsboard.server.common.data.DeviceTransportType;
55   -import org.thingsboard.server.common.data.device.profile.TkTcpDeviceProfileTransportConfiguration;
56   -import org.thingsboard.server.common.data.id.DeviceId;
57   -import org.thingsboard.server.common.data.rpc.RpcStatus;
58   -import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
59   -import org.thingsboard.server.common.data.yunteng.dto.TkThingsModel;
60   -import org.thingsboard.server.common.data.yunteng.enums.AttributeSourceDataTypeEnum;
61   -import org.thingsboard.server.common.data.yunteng.enums.ProtocolAnalysisEnum;
62 25 import org.thingsboard.server.common.data.yunteng.utils.*;
63   -import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
64   -import org.thingsboard.server.common.transport.SessionMsgListener;
65 26 import org.thingsboard.server.common.transport.TransportService;
66   -import org.thingsboard.server.common.transport.TransportServiceCallback;
67   -import org.thingsboard.server.common.transport.adaptor.AdaptorException;
68   -import org.thingsboard.server.common.transport.auth.SessionInfoCreator;
69   -import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
70   -import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
71   -import org.thingsboard.server.common.transport.service.DefaultTransportService;
72   -import org.thingsboard.server.common.transport.service.SessionMetaData;
73   -import org.thingsboard.server.gen.transport.TransportProtos;
74   -import org.thingsboard.server.transport.tcp.adaptors.TcpAuthEntry;
75   -import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor;
76   -import org.thingsboard.server.transport.tcp.adaptors.TcpUpEntry;
77   -import org.thingsboard.server.transport.tcp.script.TkScriptFactory;
78   -import org.thingsboard.server.transport.tcp.script.TkScriptInvokeService;
79 27 import org.thingsboard.server.transport.tcp.session.TcpDeviceSessionCtx;
80 28 import org.thingsboard.server.transport.tcp.session.TcpGatewaySessionHandler;
81 29 import org.thingsboard.server.transport.tcp.util.ByteBufUtils;
82 30
  31 +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED;
  32 +
83 33 /**
84 34 * @author Andrew Shvayka
85 35 */
86 36 @Slf4j
87   -public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>>, SessionMsgListener {
88   -
89   -
90   - private final UUID sessionId;
91   - private final TcpTransportContext context;
92   - private final TransportService transportService;
93   - private final SslHandler sslHandler;
94   -
95   -
96   - /**
97   - * 需要处理的消息队列,例如:需要下发给设备的,设备上传的。
98   - */
99   - final TcpDeviceSessionCtx deviceSessionCtx;
100   - volatile InetSocketAddress address;
101   -
102   - volatile TcpGatewaySessionHandler gatewaySessionHandler;
103   - private final AtomicInteger authedCounter = new AtomicInteger();
104   -
105   -
106   - TcpTransportHandler(TcpTransportContext context, SslHandler sslHandler) {
107   - this.sessionId = UUID.randomUUID();
108   - this.context = context;
109   - this.transportService = context.getTransportService();
110   - this.sslHandler = sslHandler;
111   - this.deviceSessionCtx = new TcpDeviceSessionCtx(sessionId, context);
112   - }
113   -
114   - @Override
115   - public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
116   - super.channelRegistered(ctx);
117   - context.channelRegistered();
118   - }
119   -
120   - @Override
121   - public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
122   - super.channelUnregistered(ctx);
123   - context.channelUnregistered();
124   - }
125   -
126   - @Override
127   - public void channelRead(ChannelHandlerContext ctx, Object msg) {
128   - log.trace("【{}】 Processing msg: 【{}】", sessionId, msg);
129   - try {
130   - if(!context.isReady()){
131   - ctx.close();
132   - return;
133   - }
134   - if (address == null) {
135   - address = getAddress(ctx);
136   - }
137   - if (msg instanceof ByteBuf) {
138   - ByteBuf message = (ByteBuf) msg;
139   - byte[] byteMsg = ByteBufUtils.buf2Bytes(message);
140   - String msgStr = ByteUtils.bytesToStr(byteMsg);
141   - log.debug("会话【{}】收到设备【{}】来自【{}】数据【{}】", sessionId, deviceSessionCtx.getDeviceId(), address, msgStr);
142   - deviceSessionCtx.setChannel(ctx);
143   - if (deviceSessionCtx.getDeviceInfo() == null || deviceSessionCtx.getDeviceProfile() == null) {
144   - processConnect(ctx, msgStr);
145   - } else {
146   - enqueueRegularSessionMsg(ctx, msgStr);
147   - }
148   -
149   - } else {
150   - log.debug("【{}】 Received non tcp message: 【{}】", sessionId, msg.getClass().getSimpleName());
151   - ctx.close();
152   - }
153   - } finally {
154   - ReferenceCountUtil.safeRelease(msg);
155   - }
156   - }
157   -
158   - InetSocketAddress getAddress(ChannelHandlerContext ctx) {
159   - var address = ctx.channel().attr(TcpTransportService.ADDRESS).get();
160   - if (address == null) {
161   - log.trace("[{}] Received empty address.", ctx.channel().id());
162   - InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
163   - log.trace("[{}] Going to use address: {}", ctx.channel().id(), remoteAddress);
164   - return remoteAddress;
165   - } else {
166   - log.trace("[{}] Received address: {}", ctx.channel().id(), address);
167   - }
168   - return address;
169   - }
170   -
171   -
172   - void enqueueRegularSessionMsg(ChannelHandlerContext ctx, String msg) {
173   - final int queueSize = deviceSessionCtx.getMsgQueueSize();
174   - if (queueSize >= context.getMessageQueueSizePerDeviceLimit()) {
175   - log.info("Closing current session because msq queue size for device {} exceed limit {} with msgQueueSize counter {} and actual queue size {}",
176   - deviceSessionCtx.getDeviceId(), context.getMessageQueueSizePerDeviceLimit(), queueSize, deviceSessionCtx.getMsgQueueSize());
177   - ctx.close();
178   - return;
179   - }
180   -
181   - deviceSessionCtx.addToQueue(msg);
182   - processQueueMessage(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
183   -
184   - }
185   -
186   -
187   - void processQueueMessage(ChannelHandlerContext ctx) {
188   - if (!deviceSessionCtx.isConnected()) {
189   - log.trace("[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}", sessionId, deviceSessionCtx.getDeviceId(), deviceSessionCtx.getMsgQueueSize());
190   - return;
191   - }
192   - deviceSessionCtx.tryProcessQueuedMsgs(msg -> processDeviceSessionMsg(ctx, msg));
193   - }
194   -
195   -
196   - private void processDeviceSessionMsg(ChannelHandlerContext ctx, String tcpMessage) {
197   - if (!checkConnected(ctx, tcpMessage)) {
198   - return;
199   - }
200   - //判断协议类型
201   - TkTcpDeviceProfileTransportConfiguration transportConfiguration =
202   - (TkTcpDeviceProfileTransportConfiguration) deviceSessionCtx.getDeviceProfile().getProfileData().getTransportConfiguration();
203   - switch (transportConfiguration.getProtocol())
204   - {
205   - case CUSTOM:
206   - customScriptProcess(ctx,tcpMessage);
207   - break;
208   - case MODBUS_RTU:
209   - modbusRtuProcess(ctx,tcpMessage);
210   - break;
211   -
212   - }
213   - }
214   -
215   -
216   - private void modbusRtuProcess(ChannelHandlerContext ctx, String tcpMessage){
217   - //移除空格
218   - String hexString = tcpMessage.trim().replaceAll(" ","");
219   - //判断是否为16进制HEX
220   - if(hexString.matches("-?[0-9a-fA-F]+")){
221   - boolean modbusCheckResult = ModbusUtils.isValidModbusResponseFrame(hexString);
222   - //判断是否满足modbus标准,满足的才处理不满足的过滤掉
223   - if(modbusCheckResult){
224   - //根据上报的地址码,判断该条消息归属于那个设备的数据
225   - String deviceAddress = hexString.substring(0,2);
226   - int deviceCode = Integer.parseInt(deviceSessionCtx.getDeviceCode(),16);
227   - int deviceAddressCode = Integer.parseInt(deviceAddress,16);
228   - if(gatewaySessionHandler != null && deviceCode != deviceAddressCode){
229   - gatewaySessionHandler.onDeviceTelemetry(deviceAddress, null, hexString,
230   - ProtocolAnalysisEnum.MODBUS_RTU);
231   - }else{
232   - if(deviceCode == deviceAddressCode){
233   - processCustomDirectDeviceMsg(ctx, deviceSessionCtx.getPayloadAdaptor()
234   - .convertModbusHexToPublish(deviceSessionCtx,hexString).get());
235   - }
236   - }
237   - }
238   - }
239   - }
240   -
241   -
242   -
243   -
244   - private void customScriptProcess(ChannelHandlerContext ctx, String tcpMessage){
245   - deviceSessionCtx.doUpScript(tcpMessage, r -> {
246   - //根据网关上报的消息,判断消息的来源是否为网关子设备,判断依据deviceCode即设备地址码或设备标识符
247   - if (gatewaySessionHandler != null && checkMessageIsFromSensor(r.getDatas())) {
248   - processCustomGatewayDeviceMsg(ctx, r);
249   - }else{
250   - processCustomDirectDeviceMsg(ctx, r);
251   - }
252   - });
253   - }
254   -
255   - private boolean checkMessageIsFromSensor(Map<String,Object> dataMap){
256   - boolean isSensorMessage = true;
257   - String gateWayDeviceCode = deviceSessionCtx.getDeviceCode();
258   - for (Map.Entry<String,Object> entry :dataMap.entrySet()){
259   - if(entry.getKey().equals(gateWayDeviceCode)){
260   - isSensorMessage = false;
261   - break;
262   - }
263   - }
264   - return isSensorMessage;
265   - }
266   -
267   - /**
268   - * 上行脚本解析结果是否包含数据
269   - * @param datas 数据集合
270   - * @return
271   - */
272   - private boolean hasDatas(Map<String, Object> datas) {
273   - if (datas == null || datas.isEmpty()) {
274   - return false;
275   - }
276   - return true;
277   - }
278   -
279   - private void processCustomGatewayDeviceMsg(ChannelHandlerContext ctx, TcpUpEntry tcpMessage) {
280   - log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), tcpMessage);
281   - try {
282   - Map<String, Object> datas = tcpMessage.getDatas();
283   - if (hasDatas(datas)) {
284   - datas.forEach((devName, param) -> {
285   - if (TkScriptFactory.ORIGINAL_DATA_FILED.equals(devName)) {
286   - return;
287   - }
288   - if (tcpMessage.getTelemetry()) {
289   - gatewaySessionHandler.onDeviceTelemetry(devName, tcpMessage.getRequestId(), param.toString(),
290   - ProtocolAnalysisEnum.CUSTOM);
291   - } else {
292   -// gatewaySessionHandler.onDeviceRpcResponse(devName, tcpMessage.getRequestId(), param.toString());
293   - }
294   -
295   - });
296   - } else {
297   - transportService.reportActivity(deviceSessionCtx.getSessionInfo());
298   - pushDeviceMsg(ctx, tcpMessage.getAckMsg());
299   - }
300   - } catch (Exception e) {
301   - log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e);
302   - ctx.close();
303   - }
304   - }
305   -
306   - private void processCustomDirectDeviceMsg(ChannelHandlerContext ctx, TcpUpEntry tcpMessage) {
307   - log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), tcpMessage);
308   - try {
309   - TcpTransportAdaptor payloadAdaptor = deviceSessionCtx.getPayloadAdaptor();
310   - Map<String, Object> datas = tcpMessage.getDatas();
311   - if (hasDatas(datas)) {
312   - String dataStr = JacksonUtil.toString(datas);
313   - if (tcpMessage.getTelemetry()) {
314   - TransportProtos.PostTelemetryMsg postTelemetryMsg = payloadAdaptor.convertToPostTelemetry(deviceSessionCtx, dataStr);
315   - transportService.process(deviceSessionCtx.getSessionInfo(), postTelemetryMsg, getPubAckCallback(ctx, tcpMessage));
316   - } else {
317   - TransportProtos.ToDeviceRpcResponseMsg postRpcMsg = payloadAdaptor.convertToDeviceRpcResponse(deviceSessionCtx, tcpMessage);
318   - transportService.process(deviceSessionCtx.getSessionInfo(), postRpcMsg, getPubAckCallback(ctx, tcpMessage));
319   - }
320   - } else {
321   - transportService.reportActivity(deviceSessionCtx.getSessionInfo());
322   - pushDeviceMsg(ctx, tcpMessage.getAckMsg());
323   - }
324   - } catch (AdaptorException e) {
325   - log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e);
326   - ctx.close();
327   - }
328   - }
329   -
330   -
331   - private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final TcpUpEntry msg) {
332   - return new TransportServiceCallback<>() {
333   - @Override
334   - public void onSuccess(Void dummy) {
335   - log.trace("[{}] Published msg: {}", sessionId, msg);
336   - if (StringUtils.isNotEmpty(msg.getAckMsg())) {
337   - pushDeviceMsg(ctx, msg.getAckMsg());
338   - }
339   - }
340   -
341   - @Override
342   - public void onError(Throwable e) {
343   - log.trace("[{}] Failed to publish msg: {}", sessionId, msg, e);
344   - ctx.close();
345   - }
346   - };
347   - }
348   -
349   -
350   - void processConnect(ChannelHandlerContext ctx, String accessToken) {
351   - log.debug("[{}][{}] Processing connect msg for client: {}!", address, sessionId, accessToken);
352   -
353   - if (DataConstants.PROVISION.equals(accessToken) || DataConstants.PROVISION.equals(accessToken)) {
354   - deviceSessionCtx.setProvisionOnly(true);
355   - pushDeviceMsg(ctx,CONNECTION_ACCEPTED.name());
356   - } else {
357   - TkScriptInvokeService.authScripts.forEach(id -> {
358   - ListenableFuture item = context.getJsEngine().invokeFunction(id, accessToken);
359   - Futures.addCallback(item, new FutureCallback<String>() {
360   - @Override
361   - public void onSuccess(@Nullable String result) {
362   - processAuthTokenConnect(ctx, id, JacksonUtil.fromString(result.replace("\\","\\\\"), TcpAuthEntry.class));
363   - }
364   -
365   - @Override
366   - public void onFailure(Throwable t) {
367   - onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_PAYLOAD_FORMAT_INVALID);
368   - }
369   - }, MoreExecutors.directExecutor());
370   -
371   - });
372   - }
373   - }
374   -
375   - private void processAuthTokenConnect(ChannelHandlerContext ctx, UUID scriptId, TcpAuthEntry accessToken) {
376   -
377   - log.debug("[{}][{}] Processing connect msg for client with user name: {}!", address, sessionId, accessToken);
378   - if (null != accessToken.getClientId()) {
379   - }
380   - if (null != accessToken.getUserName()) {
381   - }
382   - String token = accessToken.getPassword();
383   - if(StringUtils.isNotEmpty(token)){
384   - TransportProtos.ValidateDeviceTokenRequestMsg.Builder request = TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder();
385   - request.setToken(token);
386   - transportService.process(DeviceTransportType.TCP, request.build(),
387   - new TransportServiceCallback<>() {
388   - @Override
389   - public void onSuccess(ValidateDeviceCredentialsResponse msg) {
390   - onValidateDeviceResponse(msg, ctx, accessToken, scriptId);
391   - }
392   -
393   - @Override
394   - public void onError(Throwable e) {
395   - log.trace("[{}] Failed to process credentials: {}", address, accessToken, e);
396   - onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE);
397   - }
398   - });
399   - }else{
400   - onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_PAYLOAD_FORMAT_INVALID);
401   - }
402   - }
403   -
404   -
405   -
406   -
407   - @Override
408   - public void channelReadComplete(ChannelHandlerContext ctx) {
409   - ctx.flush();
410   - }
411   -
412   - @Override
413   - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
414   - log.error("[{}] Unexpected Exception", sessionId, cause);
  37 +public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>> {
  38 +
  39 + private final UUID sessionId;
  40 + private final TcpTransportContext context;
  41 + private final TransportService transportService;
  42 +
  43 + private TcpUdpDataHandler dataHandler = null;
  44 + /** 需要处理的消息队列,例如:需要下发给设备的,设备上传的。 */
  45 + final TcpDeviceSessionCtx deviceSessionCtx;
  46 +
  47 + volatile InetSocketAddress address;
  48 + volatile TcpGatewaySessionHandler gatewaySessionHandler;
  49 + TcpTransportHandler(TcpTransportContext context) {
  50 + this.sessionId = UUID.randomUUID();
  51 + this.context = context;
  52 + this.transportService = context.getTransportService();
  53 + this.deviceSessionCtx = new TcpDeviceSessionCtx(sessionId, context);
  54 + }
  55 +
  56 + @Override
  57 + public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
  58 + super.channelRegistered(ctx);
  59 + context.channelRegistered();
  60 + }
  61 +
  62 + @Override
  63 + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
  64 + super.channelUnregistered(ctx);
  65 + context.channelUnregistered();
  66 + }
  67 +
  68 + @Override
  69 + public void channelRead(ChannelHandlerContext ctx, Object msg) {
  70 + log.debug("【{}】 TCP channelRead Processing msg: 【{}】", sessionId, msg);
  71 + try {
  72 + if (!context.isReady()) {
415 73 ctx.close();
416   - if (cause instanceof OutOfMemoryError) {
417   - log.error("Received critical error. Going to shutdown the service.");
418   - System.exit(1);
419   - }
420   - }
421   -
422   - private static MqttSubAckMessage createSubAckMessage(Integer msgId, List<Integer> grantedQoSList) {
423   - MqttFixedHeader mqttFixedHeader =
424   - new MqttFixedHeader(SUBACK, false, AT_MOST_ONCE, false, 0);
425   - MqttMessageIdVariableHeader mqttMessageIdVariableHeader = MqttMessageIdVariableHeader.from(msgId);
426   - MqttSubAckPayload mqttSubAckPayload = new MqttSubAckPayload(grantedQoSList);
427   - return new MqttSubAckMessage(mqttFixedHeader, mqttMessageIdVariableHeader, mqttSubAckPayload);
428   - }
429   -
430   -
431   - public static MqttPubAckMessage createMqttPubAckMsg(int requestId) {
432   - MqttFixedHeader mqttFixedHeader =
433   - new MqttFixedHeader(PUBACK, false, AT_MOST_ONCE, false, 0);
434   - MqttMessageIdVariableHeader mqttMsgIdVariableHeader =
435   - MqttMessageIdVariableHeader.from(requestId);
436   - return new MqttPubAckMessage(mqttFixedHeader, mqttMsgIdVariableHeader);
437   - }
438   -
439   - private boolean checkConnected(ChannelHandlerContext ctx, String msg) {
440   - if (deviceSessionCtx.isConnected()) {
441   - return true;
442   - } else {
443   - log.info("[{}] Closing current session due to invalid msg order: {}", sessionId, msg);
444   - return false;
445   - }
446   - }
447   -
448   - private void checkGatewaySession(SessionMetaData sessionMetaData) {
449   - TransportDeviceInfo device = deviceSessionCtx.getDeviceInfo();
450   - try {
451   - JsonNode infoNode = context.getMapper().readTree(device.getAdditionalInfo());
452   - if (infoNode != null) {
453   - JsonNode gatewayNode = infoNode.get("gateway");
454   - if (gatewayNode != null && gatewayNode.asBoolean()) {
455   - gatewaySessionHandler = new TcpGatewaySessionHandler(deviceSessionCtx, sessionId);
456   - if (infoNode.has(DefaultTransportService.OVERWRITE_ACTIVITY_TIME) && infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).isBoolean()) {
457   - sessionMetaData.setOverwriteActivityTime(infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).asBoolean());
458   - }
459   - }
460   - }
461   - } catch (IOException e) {
462   - log.trace("[{}][{}] Failed to fetch device additional info", sessionId, device.getDeviceName(), e);
463   - }
464   - }
465   -
466   - @Override
467   - public void operationComplete(Future<? super Void> future) throws Exception {
468   - log.trace("[{}] Channel closed!", sessionId);
469   - doDisconnect();
470   - }
471   -
472   - public void doDisconnect() {
473   - if (deviceSessionCtx.isConnected()) {
474   - log.debug("[{}] Client disconnected!", sessionId);
475   - transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_CLOSED, null);
476   - transportService.deregisterSession(deviceSessionCtx.getSessionInfo());
477   - if (gatewaySessionHandler != null) {
478   - gatewaySessionHandler.onGatewayDisconnect();
479   - }
480   - deviceSessionCtx.setDisconnected();
481   - }
482   - deviceSessionCtx.release();
483   - }
484   -
485   -
486   - private void onValidateDeviceResponse(ValidateDeviceCredentialsResponse msg, ChannelHandlerContext ctx, TcpAuthEntry authEntry, UUID scriptId) {
487   - if (!msg.hasDeviceInfo()) {
488   - context.onAuthFailure(address);
489   - onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED);
490   - } else {
491   - DeviceProfile profile = msg.getDeviceProfile();
492   - TkTcpDeviceProfileTransportConfiguration tcpConfig = (TkTcpDeviceProfileTransportConfiguration) profile.getProfileData().getTransportConfiguration();
493   - if (scriptId != null&& tcpConfig.getProtocol().equals(ProtocolAnalysisEnum.CUSTOM) && !tcpConfig.getAuthScriptId().equals(scriptId.toString())) {
494   - authedCounter.incrementAndGet();
495   - return;
496   - }
497   - context.onAuthSuccess(address);
498   - deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo());
499   - deviceSessionCtx.setDeviceProfile(profile);
500   - deviceSessionCtx.setSessionInfo(SessionInfoCreator.create(msg, context, sessionId));
501   - transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_OPEN, new TransportServiceCallback<Void>() {
502   - @Override
503   - public void onSuccess(Void msg) {
504   - SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), TcpTransportHandler.this);
505   - checkGatewaySession(sessionMetaData);
506   - pushDeviceMsg(ctx,authEntry.getSuccess());
507   - deviceSessionCtx.setConnected(true);
508   - log.debug("[{}] Client connected!", sessionId);
509   -
510   - transportService.process(deviceSessionCtx.getSessionInfo(), TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null);
511   - transportService.getCallbackExecutor().execute(() -> processQueueMessage(ctx)); //this callback will execute in Producer worker thread and hard or blocking work have to be submitted to the separate thread.
512   - }
513   -
514   - @Override
515   - public void onError(Throwable e) {
516   - if (e instanceof TbRateLimitsException) {
517   - log.trace("[{}] Failed to submit session event: {}", sessionId, e.getMessage());
518   - } else {
519   - log.warn("[{}] Failed to submit session event", sessionId, e);
520   - }
521   - onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE);
522   - }
523   - });
524   - }
525   - }
526   -
527   - private void onValidateFailed(ChannelHandlerContext ctx, MqttConnectReturnCode msg) {
528   - authedCounter.incrementAndGet();
529   - if (TkScriptInvokeService.authScripts.size() == authedCounter.intValue()) {
530   - pushDeviceMsg(ctx,msg.name());
531   -
532   - ctx.close();
533   - }
534   - }
535   -
536   - @Override
537   - public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) {
538   -
539   - }
540   -
541   - @Override
542   - public void onAttributeUpdate(UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg notification) {
543   -
544   - }
545   -
546   - @Override
547   - public void onRemoteSessionCloseCommand(UUID sessionId, TransportProtos.SessionCloseNotificationProto sessionCloseNotification) {
548   - log.trace("[{}] Received the remote command to close the session: {}", sessionId, sessionCloseNotification.getMessage());
549   - deviceSessionCtx.getChannel().close();
550   - }
551   -
552   - @Override
553   - public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) {
554   - log.debug("【{}】下发RPC命令【{}】给设备【{}】", sessionId, rpcRequest.getParams(), deviceSessionCtx.getDeviceInfo().getDeviceName());
555   - TcpTransportAdaptor adaptor = deviceSessionCtx.getPayloadAdaptor();
556   - try {
557   - adaptor
558   - .convertToPublish(deviceSessionCtx, rpcRequest)
559   - .ifPresent(
560   - payload -> {
561   - deviceSessionCtx.rpcRequesting(payload.getIdentifier(), rpcRequest);
562   - Optional.ofNullable(pushDeviceMsg(deviceSessionCtx.getChannel(), payload.getDatas())).ifPresent(cf->{
563   - cf.addListener(
564   - result -> {
565   - if (result.cause() == null) {
566   - transportService.process(
567   - deviceSessionCtx.getSessionInfo(),
568   - rpcRequest,
569   - RpcStatus.DELIVERED,
570   - TransportServiceCallback.EMPTY);
571   - } else {
572   - // TODO: send error
573   - }
574   - });
575   - });
576   - ;
577   - });
578   - } catch (Exception e) {
579   - transportService.process(deviceSessionCtx.getSessionInfo(),
580   - TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
581   - .setRequestId(rpcRequest.getRequestId()).setError("Failed to convert device RPC command to TCP msg").build(), TransportServiceCallback.EMPTY);
582   - log.error("[{}] Failed to convert device RPC command to TCP msg", sessionId, e);
583   - }
584   - }
585   -
586   -
587   - @Override
588   - public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg rpcResponse) {
589   - log.debug("[{}] 服务端响应设备的RPC请求", sessionId);
590   - }
591   -
592   - /**
593   - * 往设备推送消息
594   - *
595   - * @param message
596   - * @return
597   - */
598   - private ChannelFuture pushDeviceMsg(ChannelHandlerContext ctx, String message) {
599   - if(StringUtils.isBlank(message)){
600   - return null;
601   - }
602   - ByteBuf buff = Unpooled.buffer();
603   - if(!message.matches("-?[0-9a-fA-F]+")){
604   - //不满足16进制将字符串转为16进制
605   - message = ByteUtils.stringEncodeToHex(message);
606   - }
607   - buff.writeBytes(ByteUtils.hexToByteArray(message));
608   - return ctx.writeAndFlush(buff);
609   - }
610   -
611   -
612   - @Override
613   - public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
614   - deviceSessionCtx.onDeviceProfileUpdate(sessionInfo, deviceProfile);
615   - }
616   -
617   - @Override
618   - public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) {
619   - deviceSessionCtx.onDeviceUpdate(sessionInfo, device, deviceProfileOpt);
620   - deviceSessionCtx.setDeviceCode(JacksonUtil.toString(device.getAdditionalInfo()));
621   - }
622   -
623   - @Override
624   - public void onDeviceDeleted(DeviceId deviceId) {
625   - context.onAuthFailure(address);
626   - ChannelHandlerContext ctx = deviceSessionCtx.getChannel();
  74 + return;
  75 + }
  76 + if (address == null) {
  77 + address = getAddress(ctx);
  78 + }
  79 + if (msg instanceof ByteBuf) {
  80 + ByteBuf message = (ByteBuf) msg;
  81 + byte[] byteMsg = ByteBufUtils.buf2Bytes(message);
  82 + String msgStr = ByteUtils.bytesToStr(byteMsg);
  83 + log.debug(
  84 + "TCP服务【{}】收到设备【{}】来自【{}】数据【{}】",
  85 + sessionId,
  86 + deviceSessionCtx.getDeviceId(),
  87 + address,
  88 + msgStr);
  89 + if(null == dataHandler){
  90 + dataHandler = new TcpUdpDataHandler(context,sessionId,deviceSessionCtx,address,gatewaySessionHandler,true);
  91 + }
  92 + dataHandler.enqueueRegularSessionMsg(ctx, msgStr);
  93 + } else {
  94 + log.debug("【{}】 Received non tcp message: 【{}】", sessionId, msg.getClass().getSimpleName());
627 95 ctx.close();
628   - }
  96 + }
  97 + } finally {
  98 + ReferenceCountUtil.safeRelease(msg);
  99 + }
  100 + }
  101 +
  102 + InetSocketAddress getAddress(ChannelHandlerContext ctx) {
  103 + var address = ctx.channel().attr(TcpTransportService.ADDRESS).get();
  104 + if (address == null) {
  105 + log.trace("[{}] Received empty address.", ctx.channel().id());
  106 + InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
  107 + log.trace("[{}] Going to use address: {}", ctx.channel().id(), remoteAddress);
  108 + return remoteAddress;
  109 + } else {
  110 + log.trace("[{}] Received address: {}", ctx.channel().id(), address);
  111 + }
  112 + return address;
  113 + }
  114 +
  115 +
  116 + @Override
  117 + public void channelReadComplete(ChannelHandlerContext ctx) {
  118 + ctx.flush();
  119 + }
  120 +
  121 + @Override
  122 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  123 + log.error("[{}] Unexpected Exception", sessionId, cause);
  124 + ctx.close();
  125 + if (cause instanceof OutOfMemoryError) {
  126 + log.error("Received critical error. Going to shutdown the service.");
  127 + System.exit(1);
  128 + }
  129 + }
  130 +
  131 + @Override
  132 + public void operationComplete(Future<? super Void> future) throws Exception {
  133 + log.trace("[{}] Channel closed!", sessionId);
  134 + doDisconnect();
  135 + }
  136 +
  137 + public void doDisconnect() {
  138 + if (deviceSessionCtx.isConnected()) {
  139 + log.debug("[{}] Client disconnected!", sessionId);
  140 + transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_CLOSED, null);
  141 + transportService.deregisterSession(deviceSessionCtx.getSessionInfo());
  142 + if (gatewaySessionHandler != null) {
  143 + gatewaySessionHandler.onGatewayDisconnect();
  144 + }
  145 + deviceSessionCtx.setDisconnected();
  146 + }
  147 + deviceSessionCtx.release();
  148 + }
629 149 }
... ...
... ... @@ -57,7 +57,7 @@ public class TcpTransportServerInitializer extends ChannelInitializer<SocketChan
57 57 // pipeline.addLast("decoder", new StringDecoder());
58 58 // pipeline.addLast("encoder", new StringEncoder());
59 59
60   - TcpTransportHandler handler = new TcpTransportHandler(context, sslHandler);
  60 + TcpTransportHandler handler = new TcpTransportHandler(context);
61 61
62 62 pipeline.addLast(handler);
63 63 ch.closeFuture().addListener(handler);
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/TcpUdpDataHandler.java renamed from common/transport/tcp/src/main/java/org/thingsboard/server/transport/udp/UdpDatagramDataHandler.java
1   -/**
2   - * Copyright © 2016-2022 The Thingsboard Authors
3   - *
4   - * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5   - * except in compliance with the License. You may obtain a copy of the License at
6   - *
7   - * <p>http://www.apache.org/licenses/LICENSE-2.0
8   - *
9   - * <p>Unless required by applicable law or agreed to in writing, software distributed under the
10   - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11   - * express or implied. See the License for the specific language governing permissions and
12   - * limitations under the License.
13   - */
14   -package org.thingsboard.server.transport.udp;
15   -
16   -import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED;
17   -import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN;
  1 +package org.thingsboard.server.transport.tcp;
18 2
19 3 import com.fasterxml.jackson.databind.JsonNode;
20 4 import com.google.common.util.concurrent.FutureCallback;
... ... @@ -27,21 +11,12 @@ import io.netty.buffer.Unpooled;
27 11 import io.netty.channel.ChannelFuture;
28 12 import io.netty.channel.ChannelHandlerContext;
29 13 import io.netty.channel.socket.DatagramPacket;
30   -import io.netty.handler.codec.mqtt.*;
31   -import io.netty.util.concurrent.Future;
32   -import io.netty.util.concurrent.GenericFutureListener;
33   -import java.io.IOException;
34   -import java.net.InetSocketAddress;
35   -import java.util.Map;
36   -import java.util.Optional;
37   -import java.util.UUID;
38   -import java.util.concurrent.atomic.AtomicInteger;
  14 +import io.netty.handler.codec.mqtt.MqttConnectReturnCode;
39 15 import lombok.extern.slf4j.Slf4j;
40 16 import org.apache.commons.lang3.StringUtils;
41 17 import org.checkerframework.checker.nullness.qual.Nullable;
42 18 import org.thingsboard.common.util.JacksonUtil;
43 19 import org.thingsboard.server.common.data.DataConstants;
44   -import org.thingsboard.server.common.data.Device;
45 20 import org.thingsboard.server.common.data.DeviceProfile;
46 21 import org.thingsboard.server.common.data.DeviceTransportType;
47 22 import org.thingsboard.server.common.data.device.profile.TkTcpDeviceProfileTransportConfiguration;
... ... @@ -49,6 +24,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
49 24 import org.thingsboard.server.common.data.rpc.RpcStatus;
50 25 import org.thingsboard.server.common.data.yunteng.enums.ProtocolAnalysisEnum;
51 26 import org.thingsboard.server.common.data.yunteng.utils.ByteUtils;
  27 +import org.thingsboard.server.common.data.yunteng.utils.ModbusUtils;
52 28 import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
53 29 import org.thingsboard.server.common.transport.SessionMsgListener;
54 30 import org.thingsboard.server.common.transport.TransportService;
... ... @@ -60,7 +36,6 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes
60 36 import org.thingsboard.server.common.transport.service.DefaultTransportService;
61 37 import org.thingsboard.server.common.transport.service.SessionMetaData;
62 38 import org.thingsboard.server.gen.transport.TransportProtos;
63   -import org.thingsboard.server.transport.tcp.TcpTransportContext;
64 39 import org.thingsboard.server.transport.tcp.adaptors.TcpAuthEntry;
65 40 import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor;
66 41 import org.thingsboard.server.transport.tcp.adaptors.TcpUpEntry;
... ... @@ -69,36 +44,59 @@ import org.thingsboard.server.transport.tcp.script.TkScriptInvokeService;
69 44 import org.thingsboard.server.transport.tcp.session.TcpDeviceSessionCtx;
70 45 import org.thingsboard.server.transport.tcp.session.TcpGatewaySessionHandler;
71 46
72   -/**
73   - * @author Andrew Shvayka
74   - */
75   -@Slf4j
76   -public class UdpDatagramDataHandler
77   - implements GenericFutureListener<Future<? super Void>>, SessionMsgListener {
  47 +import java.io.IOException;
  48 +import java.net.InetSocketAddress;
  49 +import java.util.Map;
  50 +import java.util.Optional;
  51 +import java.util.UUID;
  52 +import java.util.concurrent.atomic.AtomicInteger;
  53 +
  54 +import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED;
  55 +import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN;
78 56
  57 +@Slf4j
  58 +public class TcpUdpDataHandler implements SessionMsgListener {
79 59 private final UUID sessionId;
80 60 private final TcpTransportContext context;
81 61 private final TransportService transportService;
82 62
83   - /** 需要处理的消息队列,例如:需要下发给设备的,设备上传的。 */
  63 + private final boolean isTcp;
84 64 final TcpDeviceSessionCtx deviceSessionCtx;
85   -
86 65 volatile InetSocketAddress address;
87   -
88 66 volatile TcpGatewaySessionHandler gatewaySessionHandler;
89 67 private final AtomicInteger authedCounter = new AtomicInteger();
90 68
91   - UdpDatagramDataHandler(
92   - ChannelHandlerContext ctx, TcpTransportContext context, InetSocketAddress devAddress) {
  69 + volatile UdpTransportHandler udpTransportHandler;
  70 +
  71 + public TcpUdpDataHandler(UdpTransportHandler udpTransportHandler,TcpTransportContext context, InetSocketAddress address, boolean isTcp) {
93 72 super();
94 73 this.sessionId = UUID.randomUUID();
95 74 this.context = context;
96   - this.address = devAddress;
  75 + this.address = address;
97 76 this.transportService = context.getTransportService();
98 77 this.deviceSessionCtx = new TcpDeviceSessionCtx(sessionId, context);
  78 + this.isTcp = isTcp;
  79 + this.udpTransportHandler = udpTransportHandler;
99 80 }
100 81
101   - public void dealDeviceMsg(ChannelHandlerContext ctx, String msg) {
  82 + TcpUdpDataHandler(
  83 + TcpTransportContext context,
  84 + UUID sessionId,
  85 + TcpDeviceSessionCtx deviceSessionCtx,
  86 + InetSocketAddress address,
  87 + TcpGatewaySessionHandler gatewaySessionHandler,
  88 + boolean isTcp) {
  89 + super();
  90 + this.sessionId = sessionId;
  91 + this.context = context;
  92 + this.address = address;
  93 + this.transportService = context.getTransportService();
  94 + this.deviceSessionCtx = deviceSessionCtx;
  95 + this.gatewaySessionHandler = gatewaySessionHandler;
  96 + this.isTcp = isTcp;
  97 + }
  98 +
  99 + public void enqueueRegularSessionMsg(ChannelHandlerContext ctx, String msg) {
102 100 deviceSessionCtx.setChannel(ctx);
103 101 if (deviceSessionCtx.getDeviceInfo() == null || deviceSessionCtx.getDeviceProfile() == null) {
104 102 processConnect(ctx, msg);
... ... @@ -112,137 +110,15 @@ public class UdpDatagramDataHandler
112 110 context.getMessageQueueSizePerDeviceLimit(),
113 111 queueSize,
114 112 deviceSessionCtx.getMsgQueueSize());
115   - // ctx.close();
  113 + if (isTcp) {
  114 + ctx.close();
  115 + }
116 116 return;
117 117 }
118 118 deviceSessionCtx.addToQueue(msg);
119 119 processQueueMessage(
120 120 ctx); // Under the normal conditions the msg queue will contain 0 messages. Many messages
121   - // will be processed on device connect event in separate thread pool
122   - }
123   -
124   - void processQueueMessage(ChannelHandlerContext ctx) {
125   - if (!deviceSessionCtx.isConnected()) {
126   - log.trace(
127   - "[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}",
128   - sessionId,
129   - deviceSessionCtx.getDeviceId(),
130   - deviceSessionCtx.getMsgQueueSize());
131   - return;
132   - }
133   - deviceSessionCtx.tryProcessQueuedMsgs(msg -> processDeviceSessionMsg(ctx, msg));
134   - }
135   -
136   - private void processDeviceSessionMsg(ChannelHandlerContext ctx, String tcpMessage) {
137   - if (!checkConnected(ctx, tcpMessage)) {
138   - return;
139   - }
140   - deviceSessionCtx.doUpScript(
141   - tcpMessage,
142   - r -> {
143   - if (gatewaySessionHandler != null) {
144   - processGatewayDeviceMsg(ctx, r);
145   - }
146   - processDirectDeviceMsg(ctx, r);
147   - });
148   - }
149   -
150   - /**
151   - * 上行脚本解析结果是否包含数据
152   - *
153   - * @param datas 数据集合
154   - * @return
155   - */
156   - private boolean hasDatas(Map<String, Object> datas) {
157   - if (datas == null || datas.isEmpty()) {
158   - return false;
159   - }
160   - return true;
161   - }
162   -
163   - private void processGatewayDeviceMsg(ChannelHandlerContext ctx, TcpUpEntry tcpMessage) {
164   - log.trace(
165   - "[{}][{}] Processing publish msg [{}]!",
166   - sessionId,
167   - deviceSessionCtx.getDeviceId(),
168   - tcpMessage);
169   - try {
170   - Map<String, Object> datas = tcpMessage.getDatas();
171   - if (hasDatas(datas)) {
172   - datas.forEach(
173   - (devName, param) -> {
174   - if (TkScriptFactory.ORIGINAL_DATA_FILED.equals(devName)) {
175   - return;
176   - }
177   - if (tcpMessage.getTelemetry()) {
178   - gatewaySessionHandler.onDeviceTelemetry(
179   - devName, tcpMessage.getRequestId(), param.toString(), ProtocolAnalysisEnum.CUSTOM);
180   - } else {
181   - // gatewaySessionHandler.onDeviceRpcResponse(devName,
182   - // tcpMessage.getRequestId(), param.toString());
183   - }
184   - });
185   - } else {
186   - transportService.reportActivity(deviceSessionCtx.getSessionInfo());
187   - pushDeviceMsg(ctx, tcpMessage.getAckMsg());
188   - }
189   - } catch (Exception e) {
190   - log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e);
191   - // ctx.close();
192   - }
193   - }
194   -
195   - private void processDirectDeviceMsg(ChannelHandlerContext ctx, TcpUpEntry tcpMessage) {
196   - log.trace(
197   - "[{}][{}] Processing publish msg [{}]!",
198   - sessionId,
199   - deviceSessionCtx.getDeviceId(),
200   - tcpMessage);
201   - try {
202   - TcpTransportAdaptor payloadAdaptor = deviceSessionCtx.getPayloadAdaptor();
203   - Map<String, Object> datas = tcpMessage.getDatas();
204   - if (hasDatas(datas)) {
205   - String dataStr = JacksonUtil.toString(datas);
206   - if (tcpMessage.getTelemetry()) {
207   - TransportProtos.PostTelemetryMsg postTelemetryMsg =
208   - payloadAdaptor.convertToPostTelemetry(deviceSessionCtx, dataStr);
209   - transportService.process(
210   - deviceSessionCtx.getSessionInfo(),
211   - postTelemetryMsg,
212   - getPubAckCallback(ctx, tcpMessage));
213   - } else {
214   - TransportProtos.ToDeviceRpcResponseMsg postRpcMsg =
215   - payloadAdaptor.convertToDeviceRpcResponse(deviceSessionCtx, tcpMessage);
216   - transportService.process(
217   - deviceSessionCtx.getSessionInfo(), postRpcMsg, getPubAckCallback(ctx, tcpMessage));
218   - }
219   - } else {
220   - transportService.reportActivity(deviceSessionCtx.getSessionInfo());
221   - pushDeviceMsg(ctx, tcpMessage.getAckMsg());
222   - }
223   - } catch (AdaptorException e) {
224   - log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e);
225   - // ctx.close();
226   - }
227   - }
228   -
229   - private <T> TransportServiceCallback<Void> getPubAckCallback(
230   - final ChannelHandlerContext ctx, final TcpUpEntry msg) {
231   - return new TransportServiceCallback<>() {
232   - @Override
233   - public void onSuccess(Void dummy) {
234   - log.trace("[{}] Published msg: {}", sessionId, msg);
235   - if (StringUtils.isNotEmpty(msg.getAckMsg())) {
236   - pushDeviceMsg(ctx, msg.getAckMsg());
237   - }
238   - }
239   -
240   - @Override
241   - public void onError(Throwable e) {
242   - log.trace("[{}] Failed to publish msg: {}", sessionId, msg, e);
243   - // ctx.close();
244   - }
245   - };
  121 + // will be processed on device connect event in separate thread pool
246 122 }
247 123
248 124 void processConnect(ChannelHandlerContext ctx, String accessToken) {
... ... @@ -251,7 +127,7 @@ public class UdpDatagramDataHandler
251 127 if (DataConstants.PROVISION.equals(accessToken)
252 128 || DataConstants.PROVISION.equals(accessToken)) {
253 129 deviceSessionCtx.setProvisionOnly(true);
254   - pushDeviceMsg(ctx, "CONNECTION_ACCEPTED");
  130 + pushDeviceMsg(ctx, CONNECTION_ACCEPTED.name());
255 131 } else {
256 132 TkScriptInvokeService.authScripts.forEach(
257 133 id -> {
... ... @@ -278,6 +154,18 @@ public class UdpDatagramDataHandler
278 154 }
279 155 }
280 156
  157 + void processQueueMessage(ChannelHandlerContext ctx) {
  158 + if (!deviceSessionCtx.isConnected()) {
  159 + log.trace(
  160 + "[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}",
  161 + sessionId,
  162 + deviceSessionCtx.getDeviceId(),
  163 + deviceSessionCtx.getMsgQueueSize());
  164 + return;
  165 + }
  166 + deviceSessionCtx.tryProcessQueuedMsgs(msg -> processDeviceSessionMsg(ctx, msg));
  167 + }
  168 +
281 169 private void processAuthTokenConnect(
282 170 ChannelHandlerContext ctx, UUID scriptId, TcpAuthEntry accessToken) {
283 171
... ... @@ -313,53 +201,14 @@ public class UdpDatagramDataHandler
313 201 }
314 202 }
315 203
316   - private boolean checkConnected(ChannelHandlerContext ctx, String msg) {
317   - if (deviceSessionCtx.isConnected()) {
318   - return true;
319   - } else {
320   - log.info("[{}] Closing current session due to invalid msg order: {}", sessionId, msg);
321   - return false;
322   - }
323   - }
324   -
325   - private void checkGatewaySession(SessionMetaData sessionMetaData) {
326   - TransportDeviceInfo device = deviceSessionCtx.getDeviceInfo();
327   - try {
328   - JsonNode infoNode = context.getMapper().readTree(device.getAdditionalInfo());
329   - if (infoNode != null) {
330   - JsonNode gatewayNode = infoNode.get("gateway");
331   - if (gatewayNode != null && gatewayNode.asBoolean()) {
332   - gatewaySessionHandler = new TcpGatewaySessionHandler(deviceSessionCtx, sessionId);
333   - if (infoNode.has(DefaultTransportService.OVERWRITE_ACTIVITY_TIME)
334   - && infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).isBoolean()) {
335   - sessionMetaData.setOverwriteActivityTime(
336   - infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).asBoolean());
337   - }
338   - }
339   - }
340   - } catch (IOException e) {
341   - log.trace(
342   - "[{}][{}] Failed to fetch device additional info", sessionId, device.getDeviceName(), e);
343   - }
344   - }
345   -
346   - @Override
347   - public void operationComplete(Future<? super Void> future) throws Exception {
348   - log.trace("[{}] Channel closed!", sessionId);
349   - doDisconnect();
350   - }
351   -
352   - public void doDisconnect() {
353   - if (deviceSessionCtx.isConnected()) {
354   - log.debug("[{}] Client disconnected!", sessionId);
355   - transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_CLOSED, null);
356   - transportService.deregisterSession(deviceSessionCtx.getSessionInfo());
357   - if (gatewaySessionHandler != null) {
358   - gatewaySessionHandler.onGatewayDisconnect();
  204 + private void onValidateFailed(ChannelHandlerContext ctx, MqttConnectReturnCode msg) {
  205 + authedCounter.incrementAndGet();
  206 + if (TkScriptInvokeService.authScripts.size() == authedCounter.intValue()) {
  207 + pushDeviceMsg(ctx, msg.name());
  208 + if (isTcp) {
  209 + ctx.close();
359 210 }
360   - deviceSessionCtx.setDisconnected();
361 211 }
362   - deviceSessionCtx.release();
363 212 }
364 213
365 214 private void onValidateDeviceResponse(
... ... @@ -375,7 +224,9 @@ public class UdpDatagramDataHandler
375 224 TkTcpDeviceProfileTransportConfiguration tcpConfig =
376 225 (TkTcpDeviceProfileTransportConfiguration)
377 226 profile.getProfileData().getTransportConfiguration();
378   - if (scriptId != null && !tcpConfig.getAuthScriptId().equals(scriptId.toString())) {
  227 + if (scriptId != null
  228 + && tcpConfig.getProtocol().equals(ProtocolAnalysisEnum.CUSTOM)
  229 + && !tcpConfig.getAuthScriptId().equals(scriptId.toString())) {
379 230 authedCounter.incrementAndGet();
380 231 return;
381 232 }
... ... @@ -391,7 +242,7 @@ public class UdpDatagramDataHandler
391 242 public void onSuccess(Void msg) {
392 243 SessionMetaData sessionMetaData =
393 244 transportService.registerAsyncSession(
394   - deviceSessionCtx.getSessionInfo(), UdpDatagramDataHandler.this);
  245 + deviceSessionCtx.getSessionInfo(), TcpUdpDataHandler.this);
395 246 checkGatewaySession(sessionMetaData);
396 247 pushDeviceMsg(ctx, authEntry.getSuccess());
397 248 deviceSessionCtx.setConnected(true);
... ... @@ -407,8 +258,8 @@ public class UdpDatagramDataHandler
407 258 () ->
408 259 processQueueMessage(
409 260 ctx)); // this callback will execute in Producer worker thread and
410   - // hard or blocking work have to be submitted to the separate
411   - // thread.
  261 + // hard or blocking work have to be submitted to the separate
  262 + // thread.
412 263 }
413 264
414 265 @Override
... ... @@ -424,30 +275,236 @@ public class UdpDatagramDataHandler
424 275 }
425 276 }
426 277
427   - private void onValidateFailed(ChannelHandlerContext ctx, MqttConnectReturnCode msg) {
428   - authedCounter.incrementAndGet();
429   - if (TkScriptInvokeService.authScripts.size() == authedCounter.intValue()) {
430   - pushDeviceMsg(ctx, msg.name());
  278 + private void checkGatewaySession(SessionMetaData sessionMetaData) {
  279 + TransportDeviceInfo device = deviceSessionCtx.getDeviceInfo();
  280 + try {
  281 + JsonNode infoNode = context.getMapper().readTree(device.getAdditionalInfo());
  282 + if (infoNode != null) {
  283 + JsonNode gatewayNode = infoNode.get("gateway");
  284 + if (gatewayNode != null && gatewayNode.asBoolean()) {
  285 + gatewaySessionHandler = new TcpGatewaySessionHandler(deviceSessionCtx, sessionId);
  286 + if (infoNode.has(DefaultTransportService.OVERWRITE_ACTIVITY_TIME)
  287 + && infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).isBoolean()) {
  288 + sessionMetaData.setOverwriteActivityTime(
  289 + infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).asBoolean());
  290 + }
  291 + }
  292 + }
  293 + } catch (IOException e) {
  294 + log.trace(
  295 + "[{}][{}] Failed to fetch device additional info", sessionId, device.getDeviceName(), e);
  296 + }
  297 + }
  298 +
  299 + private void processDeviceSessionMsg(ChannelHandlerContext ctx, String tcpMessage) {
  300 + if (!checkConnected(tcpMessage)) {
  301 + return;
  302 + }
  303 + // 判断协议类型
  304 + TkTcpDeviceProfileTransportConfiguration transportConfiguration =
  305 + (TkTcpDeviceProfileTransportConfiguration)
  306 + deviceSessionCtx.getDeviceProfile().getProfileData().getTransportConfiguration();
  307 + switch (transportConfiguration.getProtocol()) {
  308 + case CUSTOM:
  309 + customScriptProcess(ctx, tcpMessage);
  310 + break;
  311 + case MODBUS_RTU:
  312 + modbusRtuProcess(ctx, tcpMessage);
  313 + break;
  314 + }
  315 + }
  316 +
  317 + private void modbusRtuProcess(ChannelHandlerContext ctx, String tcpMessage) {
  318 + // 移除空格
  319 + String hexString = tcpMessage.trim().replaceAll(" ", "");
  320 + // 判断是否为16进制HEX
  321 + if (hexString.matches("-?[0-9a-fA-F]+")) {
  322 + boolean modbusCheckResult = ModbusUtils.isValidModbusResponseFrame(hexString);
  323 + // 判断是否满足modbus标准,满足的才处理不满足的过滤掉
  324 + if (modbusCheckResult) {
  325 + // 根据上报的地址码,判断该条消息归属于那个设备的数据
  326 + String deviceAddress = hexString.substring(0, 2);
  327 + int deviceCode = Integer.parseInt(deviceSessionCtx.getDeviceCode(), 16);
  328 + int deviceAddressCode = Integer.parseInt(deviceAddress, 16);
  329 + if (gatewaySessionHandler != null && deviceCode != deviceAddressCode) {
  330 + gatewaySessionHandler.onDeviceTelemetry(
  331 + deviceAddress, null, hexString, ProtocolAnalysisEnum.MODBUS_RTU);
  332 + } else {
  333 + if (deviceCode == deviceAddressCode) {
  334 + processCustomDirectDeviceMsg(
  335 + ctx,
  336 + deviceSessionCtx
  337 + .getPayloadAdaptor()
  338 + .convertModbusHexToPublish(deviceSessionCtx, hexString)
  339 + .get());
  340 + }
  341 + }
  342 + }
  343 + }
  344 + }
  345 +
  346 + private void customScriptProcess(ChannelHandlerContext ctx, String tcpMessage) {
  347 + deviceSessionCtx.doUpScript(
  348 + tcpMessage,
  349 + r -> {
  350 + // 根据网关上报的消息,判断消息的来源是否为网关子设备,判断依据deviceCode即设备地址码或设备标识符
  351 + if (gatewaySessionHandler != null && checkMessageIsFromSensor(r.getDatas())) {
  352 + processCustomGatewayDeviceMsg(ctx, r);
  353 + } else {
  354 + processCustomDirectDeviceMsg(ctx, r);
  355 + }
  356 + });
  357 + }
  358 +
  359 + private boolean checkMessageIsFromSensor(Map<String, Object> dataMap) {
  360 + boolean isSensorMessage = true;
  361 + String gateWayDeviceCode = deviceSessionCtx.getDeviceCode();
  362 + for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
  363 + if (entry.getKey().equals(gateWayDeviceCode)) {
  364 + isSensorMessage = false;
  365 + break;
  366 + }
  367 + }
  368 + return isSensorMessage;
  369 + }
  370 +
  371 + private boolean checkConnected(String msg) {
  372 + if (deviceSessionCtx.isConnected()) {
  373 + return true;
  374 + } else {
  375 + log.info("[{}] Closing current session due to invalid msg order: {}", sessionId, msg);
  376 + return false;
  377 + }
  378 + }
  379 +
  380 + private void processCustomGatewayDeviceMsg(ChannelHandlerContext ctx, TcpUpEntry tcpMessage) {
  381 + log.trace(
  382 + "[{}][{}] Processing publish msg [{}]!",
  383 + sessionId,
  384 + deviceSessionCtx.getDeviceId(),
  385 + tcpMessage);
  386 + try {
  387 + Map<String, Object> datas = tcpMessage.getDatas();
  388 + if (hasDatas(datas)) {
  389 + datas.forEach(
  390 + (devName, param) -> {
  391 + if (TkScriptFactory.ORIGINAL_DATA_FILED.equals(devName)) {
  392 + return;
  393 + }
  394 + if (tcpMessage.getTelemetry()) {
  395 + gatewaySessionHandler.onDeviceTelemetry(
  396 + devName,
  397 + tcpMessage.getRequestId(),
  398 + param.toString(),
  399 + ProtocolAnalysisEnum.CUSTOM);
  400 + } else {
  401 + // gatewaySessionHandler.onDeviceRpcResponse(devName,
  402 + // tcpMessage.getRequestId(), param.toString());
  403 + }
  404 + });
  405 + } else {
  406 + transportService.reportActivity(deviceSessionCtx.getSessionInfo());
  407 + pushDeviceMsg(ctx, tcpMessage.getAckMsg());
  408 + }
  409 + } catch (Exception e) {
  410 + log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e);
  411 + if (isTcp) {
  412 + ctx.close();
  413 + }
  414 + }
  415 + }
431 416
432   - // ctx.close();
  417 + private void processCustomDirectDeviceMsg(ChannelHandlerContext ctx, TcpUpEntry tcpMessage) {
  418 + log.trace(
  419 + "[{}][{}] Processing publish msg [{}]!",
  420 + sessionId,
  421 + deviceSessionCtx.getDeviceId(),
  422 + tcpMessage);
  423 + try {
  424 + TcpTransportAdaptor payloadAdaptor = deviceSessionCtx.getPayloadAdaptor();
  425 + Map<String, Object> datas = tcpMessage.getDatas();
  426 + if (hasDatas(datas)) {
  427 + String dataStr = JacksonUtil.toString(datas);
  428 + if (tcpMessage.getTelemetry()) {
  429 + TransportProtos.PostTelemetryMsg postTelemetryMsg =
  430 + payloadAdaptor.convertToPostTelemetry(deviceSessionCtx, dataStr);
  431 + transportService.process(
  432 + deviceSessionCtx.getSessionInfo(),
  433 + postTelemetryMsg,
  434 + getPubAckCallback(ctx, tcpMessage));
  435 + } else {
  436 + TransportProtos.ToDeviceRpcResponseMsg postRpcMsg =
  437 + payloadAdaptor.convertToDeviceRpcResponse(deviceSessionCtx, tcpMessage);
  438 + transportService.process(
  439 + deviceSessionCtx.getSessionInfo(), postRpcMsg, getPubAckCallback(ctx, tcpMessage));
  440 + }
  441 + } else {
  442 + transportService.reportActivity(deviceSessionCtx.getSessionInfo());
  443 + pushDeviceMsg(ctx, tcpMessage.getAckMsg());
  444 + }
  445 + } catch (AdaptorException e) {
  446 + log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e);
  447 + if (isTcp) {
  448 + ctx.close();
  449 + }
433 450 }
434 451 }
435 452
  453 + private <T> TransportServiceCallback<Void> getPubAckCallback(
  454 + final ChannelHandlerContext ctx, final TcpUpEntry msg) {
  455 + return new TransportServiceCallback<>() {
  456 + @Override
  457 + public void onSuccess(Void dummy) {
  458 + log.trace("[{}] Published msg: {}", sessionId, msg);
  459 + if (StringUtils.isNotEmpty(msg.getAckMsg())) {
  460 + pushDeviceMsg(ctx, msg.getAckMsg());
  461 + }
  462 + }
  463 +
  464 + @Override
  465 + public void onError(Throwable e) {
  466 + log.trace("[{}] Failed to publish msg: {}", sessionId, msg, e);
  467 + if (isTcp) {
  468 + ctx.close();
  469 + }
  470 + }
  471 + };
  472 + }
  473 +
  474 + /**
  475 + * 上行脚本解析结果是否包含数据
  476 + *
  477 + * @param datas 数据集合
  478 + * @return
  479 + */
  480 + private boolean hasDatas(Map<String, Object> datas) {
  481 + if (datas == null || datas.isEmpty()) {
  482 + return false;
  483 + }
  484 + return true;
  485 + }
  486 +
436 487 @Override
437   - public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) {}
  488 + public void onGetAttributesResponse(
  489 + TransportProtos.GetAttributeResponseMsg getAttributesResponse) {}
438 490
439 491 @Override
440 492 public void onAttributeUpdate(
441   - UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg notification) {}
  493 + UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification) {}
442 494
443 495 @Override
444 496 public void onRemoteSessionCloseCommand(
445 497 UUID sessionId, TransportProtos.SessionCloseNotificationProto sessionCloseNotification) {
446   - log.trace(
447   - "[{}] Received the remote command to close the session: {}",
  498 + log.info(
  499 + "isTcp device[{}] ,[{}] Received the remote command to close the session: {}",isTcp,
448 500 sessionId,
449 501 sessionCloseNotification.getMessage());
450   - // deviceSessionCtx.getChannel().close();
  502 + if(isTcp){
  503 + deviceSessionCtx.getChannel().close();
  504 + }else{
  505 + //UDP只能移除缓存
  506 + udpTransportHandler.remove(address);
  507 + }
451 508 }
452 509
453 510 @Override
... ... @@ -497,14 +554,24 @@ public class UdpDatagramDataHandler
497 554 }
498 555
499 556 @Override
500   - public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg rpcResponse) {
  557 + public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) {
501 558 log.debug("[{}] 服务端响应设备的RPC请求", sessionId);
502 559 }
503 560
  561 + @Override
  562 + public void onDeviceDeleted(DeviceId deviceId) {
  563 + context.onAuthFailure(address);
  564 + if (isTcp) {
  565 + ChannelHandlerContext ctx = deviceSessionCtx.getChannel();
  566 + ctx.close();
  567 + }
  568 + }
  569 +
504 570 /**
505 571 * 往设备推送消息
506 572 *
507   - * @param message
  573 + * @param ctx 上下文
  574 + * @param message 消息内容
508 575 * @return
509 576 */
510 577 private ChannelFuture pushDeviceMsg(ChannelHandlerContext ctx, String message) {
... ... @@ -517,28 +584,10 @@ public class UdpDatagramDataHandler
517 584 message = ByteUtils.stringEncodeToHex(message);
518 585 }
519 586 buff.writeBytes(ByteBufUtil.decodeHexDump(message));
  587 + if (isTcp) {
  588 + return ctx.writeAndFlush(buff);
  589 + }
520 590 DatagramPacket packet = new DatagramPacket(buff, address);
521 591 return ctx.writeAndFlush(packet);
522 592 }
523   -
524   - @Override
525   - public void onDeviceProfileUpdate(
526   - TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
527   - deviceSessionCtx.onDeviceProfileUpdate(sessionInfo, deviceProfile);
528   - }
529   -
530   - @Override
531   - public void onDeviceUpdate(
532   - TransportProtos.SessionInfoProto sessionInfo,
533   - Device device,
534   - Optional<DeviceProfile> deviceProfileOpt) {
535   - deviceSessionCtx.onDeviceUpdate(sessionInfo, device, deviceProfileOpt);
536   - }
537   -
538   - @Override
539   - public void onDeviceDeleted(DeviceId deviceId) {
540   - context.onAuthFailure(address);
541   - ChannelHandlerContext ctx = deviceSessionCtx.getChannel();
542   - // ctx.close();
543   - }
544 593 }
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/UdpTransportHandler.java renamed from common/transport/tcp/src/main/java/org/thingsboard/server/transport/udp/UdpTransportHandler.java
... ... @@ -13,29 +13,20 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.transport.udp;
17   -
18   -
19   -
20   -import io.netty.buffer.ByteBuf;
21   -import io.netty.buffer.Unpooled;
22   -import io.netty.channel.ChannelFuture;
  16 +package org.thingsboard.server.transport.tcp;
23 17 import io.netty.channel.ChannelHandlerContext;
24 18 import io.netty.channel.ChannelInboundHandlerAdapter;
25 19 import io.netty.channel.socket.DatagramPacket;
26   -import io.netty.handler.codec.mqtt.*;
27 20 import io.netty.util.ReferenceCountUtil;
28 21 import io.netty.util.concurrent.Future;
29   -import io.netty.util.concurrent.GenericFutureListener;
30 22 import java.net.InetSocketAddress;
31   -import java.util.Map;
32 23 import java.util.UUID;
33 24 import java.util.concurrent.ConcurrentHashMap;
34 25 import java.util.concurrent.ConcurrentMap;
  26 +
  27 +import io.netty.util.concurrent.GenericFutureListener;
35 28 import lombok.extern.slf4j.Slf4j;
36   -import org.apache.commons.lang3.StringUtils;
37 29 import org.thingsboard.server.common.data.yunteng.utils.ByteUtils;
38   -import org.thingsboard.server.transport.tcp.TcpTransportContext;
39 30 import org.thingsboard.server.transport.tcp.util.ByteBufUtils;
40 31
41 32 /**
... ... @@ -48,10 +39,11 @@ import org.thingsboard.server.transport.tcp.util.ByteBufUtils;
48 39 private final TcpTransportContext context;
49 40
50 41
  42 +
51 43 /**
52 44 * 需要处理的消息队列,例如:需要下发给设备的,设备上传的。
53 45 */
54   - private final ConcurrentMap<InetSocketAddress, UdpDatagramDataHandler> deviceSessiones = new ConcurrentHashMap<>();
  46 + private final ConcurrentMap<InetSocketAddress, TcpUdpDataHandler> deviceSessiones = new ConcurrentHashMap<>();
55 47
56 48
57 49 UdpTransportHandler(TcpTransportContext context) {
... ... @@ -62,19 +54,21 @@ import org.thingsboard.server.transport.tcp.util.ByteBufUtils;
62 54
63 55 @Override
64 56 public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
  57 + //启动时注册
65 58 super.channelRegistered(ctx);
66 59 context.channelRegistered();
67 60 }
68 61
69 62 @Override
70 63 public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
  64 + //停止时注销
71 65 super.channelUnregistered(ctx);
72 66 context.channelUnregistered();
73 67 }
74 68
75 69 @Override
76 70 public void channelRead(ChannelHandlerContext ctx, Object msg) {
77   - log.error("【{}】 Processing msg: 【{}】", sessionId, msg);
  71 + log.debug("【{}】 UDP channelRead Processing msg: 【{}】", sessionId, msg);
78 72 try {
79 73 if(!context.isReady()){
80 74 return;
... ... @@ -84,9 +78,9 @@ import org.thingsboard.server.transport.tcp.util.ByteBufUtils;
84 78 InetSocketAddress address = getAddress(message,ctx);
85 79 byte[] byteMsg = ByteBufUtils.buf2Bytes(message.content());
86 80 String msgStr = ByteUtils.bytesToStr(byteMsg);
87   - log.error("UDP服务【{}】收到来自【{}】数据【{}】", sessionId, address, msgStr);
88   - UdpDatagramDataHandler dataHandler = deviceSessiones.computeIfAbsent(address,k->new UdpDatagramDataHandler(ctx,context,address));
89   - dataHandler.dealDeviceMsg(ctx,msgStr);
  81 + log.debug("UDP服务【{}】收到来自【{}】数据【{}】", sessionId, address, msgStr);
  82 + TcpUdpDataHandler dataHandler = deviceSessiones.computeIfAbsent(address, k->new TcpUdpDataHandler(this,context,address,false));
  83 + dataHandler.enqueueRegularSessionMsg(ctx,msgStr);
90 84 } else {
91 85 log.debug("【{}】 Received non tcp message: 【{}】", sessionId, msg.getClass().getSimpleName());
92 86 ctx.close();
... ... @@ -109,30 +103,6 @@ import org.thingsboard.server.transport.tcp.util.ByteBufUtils;
109 103 return address;
110 104 }
111 105
112   -
113   -
114   -
115   -
116   -
117   -
118   - /**
119   - * 上行脚本解析结果是否包含数据
120   - * @param datas 数据集合
121   - * @return
122   - */
123   - private boolean hasDatas(Map<String, Object> datas) {
124   - if (datas == null || datas.isEmpty()) {
125   - return false;
126   - }
127   - return true;
128   - }
129   -
130   -
131   -
132   -
133   -
134   -
135   -
136 106 @Override
137 107 public void channelReadComplete(ChannelHandlerContext ctx) {
138 108 ctx.flush();
... ... @@ -148,34 +118,13 @@ import org.thingsboard.server.transport.tcp.util.ByteBufUtils;
148 118 }
149 119 }
150 120
151   -
152   -
153 121 @Override
154   - public void operationComplete(Future<? super Void> future) throws Exception {
155   - log.trace("[{}] Channel closed!", sessionId);
  122 + public void operationComplete(Future<? super Void> future){
  123 + log.debug("[{}] Channel closed!", sessionId);
156 124 }
157 125
158   -
159   -
160   -
161   -
162   - /**
163   - * 往设备推送消息
164   - *
165   - * @param message
166   - * @return
167   - */
168   - private ChannelFuture pushDeviceMsg(ChannelHandlerContext ctx, String message) {
169   - if(StringUtils.isBlank(message)){
170   - return null;
171   - }
172   - ByteBuf buff = Unpooled.buffer();
173   - if(!message.matches("-?[0-9a-fA-F]+")){
174   - //不满足16进制将字符串转为16进制
175   - message = ByteUtils.stringEncodeToHex(message);
176   - }
177   - buff.writeBytes(ByteUtils.hexToByteArray(message));
178   - return ctx.writeAndFlush(buff);
  126 + public void remove( InetSocketAddress address){
  127 + log.debug("remove remote device address 【{}】",address);
  128 + this.deviceSessiones.remove(address);
179 129 }
180   -
181 130 }
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/UdpTransportServerInitializer.java renamed from common/transport/tcp/src/main/java/org/thingsboard/server/transport/udp/UdpTransportServerInitializer.java
... ... @@ -13,13 +13,11 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.transport.udp;
  16 +package org.thingsboard.server.transport.tcp;
17 17
18 18 import io.netty.channel.Channel;
19 19 import io.netty.channel.ChannelInitializer;
20 20 import io.netty.channel.ChannelPipeline;
21   -import io.netty.handler.ssl.SslHandler;
22   -import org.thingsboard.server.transport.tcp.TcpTransportContext;
23 21
24 22 /**
25 23 * @author Andrew Shvayka
... ... @@ -27,21 +25,14 @@ import org.thingsboard.server.transport.tcp.TcpTransportContext;
27 25 public class UdpTransportServerInitializer extends ChannelInitializer<Channel> {
28 26
29 27 private final TcpTransportContext context;
30   - private final boolean sslEnabled;
31 28
32 29 public UdpTransportServerInitializer(TcpTransportContext context, boolean sslEnabled) {
33 30 this.context = context;
34   - this.sslEnabled = sslEnabled;
35 31 }
36   -
37 32 @Override
38 33 public void initChannel(Channel ch) {
39 34 ChannelPipeline pipeline = ch.pipeline();
40   - SslHandler sslHandler = null;
41   -
42 35 UdpTransportHandler handler = new UdpTransportHandler(context);
43   -// NettyUdpServerHandler handler = new NettyUdpServerHandler();
44   -
45 36 pipeline.addLast(handler);
46 37 ch.closeFuture().addListener(handler);
47 38 }
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/UdpTransportService.java renamed from common/transport/tcp/src/main/java/org/thingsboard/server/transport/udp/UdpTransportService.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.transport.udp;
  16 +package org.thingsboard.server.transport.tcp;
17 17
18 18 import io.netty.bootstrap.Bootstrap;
19 19 import io.netty.buffer.PooledByteBufAllocator;
... ... @@ -31,7 +31,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
31 31 import org.springframework.stereotype.Service;
32 32 import org.thingsboard.server.common.data.DataConstants;
33 33 import org.thingsboard.server.common.data.TbTransportService;
34   -import org.thingsboard.server.transport.tcp.TcpTransportContext;
35 34
36 35 import javax.annotation.PostConstruct;
37 36 import javax.annotation.PreDestroy;
... ... @@ -81,7 +80,7 @@ public class UdpTransportService implements TbTransportService {
81 80 log.info("Setting resource leak detector level to {}", leakDetectorLevel);
82 81 ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.valueOf(leakDetectorLevel.toUpperCase()));
83 82
84   - log.info("Starting TCP transport...");
  83 + log.info("Starting UDP transport...");
85 84 bossGroup = new NioEventLoopGroup(bossGroupThreadCount);
86 85 Bootstrap b = new Bootstrap();
87 86 b.group(bossGroup)
... ... @@ -98,12 +97,12 @@ public class UdpTransportService implements TbTransportService {
98 97 .option(ChannelOption.SO_BROADCAST, true);
99 98 sslServerChannel = b.bind(sslHost, sslPort).sync().channel();
100 99 }
101   - log.info("TCP transport started!");
  100 + log.info("UDP transport started!");
102 101 }
103 102
104 103 @PreDestroy
105 104 public void shutdown() throws InterruptedException {
106   - log.info("Stopping TCP transport!");
  105 + log.info("Stopping UDP transport!");
107 106 try {
108 107 serverChannel.close().sync();
109 108 if (sslEnabled) {
... ... @@ -112,7 +111,7 @@ public class UdpTransportService implements TbTransportService {
112 111 } finally {
113 112 bossGroup.shutdownGracefully();
114 113 }
115   - log.info("TCP transport stopped!");
  114 + log.info("UDP transport stopped!");
116 115 }
117 116
118 117 @Override
... ...