TCP设备接入
# 一、开启TCP服务
TCP开启在application.yml文件中控制。
提示
tcp.enabled: 开启后, TCP服务器启动连接设备
openws: 开启后,配合TCP服务,推送设备消息至前端实时更新

# 二、TCP设备连接
# 1. 注册包:
由于TCP设备连接,需要识别设备,因此TCP客户端连接时,上报的第一个报文为客户端的注册包。
例如:7e80D4AD203F3A1C7e
其中 7e 是包头包尾
80是注册包的标识位
D4AD203F3A1C 是设备编号
2
3
4
5
6
客户端上报注册包后,更新设备状态为在线
# 2. 心跳包:
TCP需要主动发送消息来维持设备的心跳保持,上图中 keep-alive 是心跳超时的判定时间 70s,因此设备的心跳需要维持在70s以下。
心跳包例如: 7e817e
7e 是包头包尾,81是标识位 (心跳包只是维持TCP长连接,一般无其他实际意义)
# 3. 特殊的注册,心跳 数据包:
在有些设备客户端,会把设备的注册包,心跳包,数据包,定时上报,一方面是包含了设备编号,也可以维持了心跳,数据包还包含了设备上报的信息,这种情况系统也是可以支持的。
# 三、TCP模拟客户端测试
模拟客户端放在如下文件

# 1. 模拟客户端上线
发送注册包:配置好后,点击链接,发送注册包,如下
7e80D4AD203F3A1C7e
这个时候,看下本地启动服务可以看到
- a. TCP客户端上线
- b. 更新TCP客户的状态
- c. 记录设备事件记录


# 2. 模拟TCP客户端断电或 断开
断电需要等待设备心跳超时(70S), 断开连接是,是实时上报设备状态
断开连接是,打印信息如下,更新设备上下线状态,新增设备事件记录,前端ws推送实时更新


同样模拟客户端断电,需要等待客户端超过心跳超时时间 (70s),更新动作跟设备断开一致。
# 四、TCP客户端前端连接展示
新建产品,选择TCP传输协议,通讯协议可以选择 JSON,Modbus-rtu协议
新建产品后,选中产品新建设备即可。
# 五、TCP + MODBUS
云端轮询,用模拟设备可以看到下发到设备的读指令,如下:

目前采用云端modbus轮询,采集数据,具体步骤,可以参考MQTT+MODBUS轮询方案
# 六、TCP+JSON
TCP设备上报格式是JSON数据,新建产品时候,选择JSON协议,新增好物模型,就可以上报数据到云平台。具体可以参考 MQTT+JSON
# 七、TCP客户端指令下发
如下图所示:

查看模拟模拟客户端可以看到,写指令下发成功,如下图所示:
# 八、TCP数据包,粘包,分包处理
# TCP粘包拆包发生场景
- 因为TCP是面向流,没有边界,而操作系统在发送TCP数据时,会通过缓冲区来进行优化,例如缓冲区为1024个字节大小。
- 如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包问题。
- 如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包。
# 对于粘包和拆包问题,常见的解决方案有四种:
- 发送端将每个包都封装成固定的长度,比如100字节大小。如果不足100字节可通过补0或空等进行填充到指定长度;
- 发送端在每个包的末尾使用固定的分隔符,例如\r\n。如果发生拆包需等待多个包发送过来之后再找到其中的\r\n进行合并;例如,FTP协议;
- 将消息分为头部和消息体,头部中保存整个消息的长度,只有读取到足够长度的消息之后才算是读到了一个完整的消息;
- 通过自定义协议进行粘包和拆包的处理
# Netty对粘包和拆包问题的处理
Netty对解决粘包和拆包的方案做了抽象,提供了一些解码器(Decoder)来解决粘包和拆包的问题。如:
- LineBasedFrameDecoder:以行为单位进行数据包的解码;
- DelimiterBasedFrameDecoder:以特殊的符号作为分隔来进行数据包的解码;
- FixedLengthFrameDecoder:以固定长度进行数据包的解码;
- LenghtFieldBasedFrameDecode:适用于消息头包含消息长度的协议(最常用);
# FastBee的TCP服务端,解决粘包,分包问题
固定分隔符
DelimiterBasedFrameDecoder 类定义了分割符处理粘包,分包问题
TCP服务器启动处理客户端消息配置中,第二个处理类配置了粘包,分包处理在TCP启动时候,添加分隔符号
固定长度
LengthFieldAndDelimiterFrameDecoder ,固定长度配置在TCP启动时候,配置如下做固定长度处理粘包,分包问题