联调物联网平台enjoy-iot系列之内置TCP协议组件
前言
1、【enjoy-iot: https://gitee.com/open-enjoy/enjoy-iot 】为乐飞智联旗下开源物联网平台,本系列文章旨在记录联调测试的过程。
2、前后端的部署均不在文章谈论范围内。
3、官方参考文档:https://y5yrmmjjns.feishu.cn/wiki/NX0bwqEEZiaU3OkmCZrcJyx7nIc?fromScene=spaceOverview
开启tcp协议组件

新增tcp系列产品


新增tcp设备


属性上报
1、新增TestTcpClient类
public class TestTcpClient {
private static byte[] encode(String addr, short code, short mid, byte[] payload) {
byte[] addrBytes = addr.getBytes(StandardCharsets.UTF_8);
byte[] body = payload == null ? new byte[0] : payload;
int length = 2 + addrBytes.length + 2 + 2 + body.length;
ByteBuffer buf = ByteBuffer.allocate(4 + length).order(ByteOrder.BIG_ENDIAN);
buf.putInt(length);
buf.putShort((short) addrBytes.length);
buf.put(addrBytes);
buf.putShort(code);
buf.putShort(mid);
buf.put(body);
return buf.array();
}
private static byte[] readPacket(InputStream in) throws Exception {
byte[] header = readFully(in, 4);
int len = ByteBuffer.wrap(header).order(ByteOrder.BIG_ENDIAN).getInt();
return readFully(in, len);
}
private static short readCode(byte[] body) {
int idx = 0;
int addrLen = ByteBuffer.wrap(Arrays.copyOfRange(body, idx, idx + 2)).order(ByteOrder.BIG_ENDIAN).getShort();
idx += 2 + addrLen;
return ByteBuffer.wrap(Arrays.copyOfRange(body, idx, idx + 2)).order(ByteOrder.BIG_ENDIAN).getShort();
}
private static byte[] readPayload(byte[] body) {
int idx = 0;
int addrLen = ByteBuffer.wrap(Arrays.copyOfRange(body, idx, idx + 2)).order(ByteOrder.BIG_ENDIAN).getShort();
idx += 2 + addrLen + 2 + 2;
return Arrays.copyOfRange(body, idx, body.length);
}
private static int readStatus(byte[] body) {
byte[] payload = readPayload(body);
if (payload.length < 4) return -1;
return ByteBuffer.wrap(payload).order(ByteOrder.BIG_ENDIAN).getInt();
}
private static byte[] readFully(InputStream in, int len) throws Exception {
byte[] data = new byte[len];
int off = 0;
while (off < len) {
int r = in.read(data, off, len - off);
if (r < 0) throw new IllegalStateException("socket closed");
off += r;
}
return data;
}
public static void main(String[] args) throws Exception {
String host = args.length > 0 ? args[0] : "127.0.0.1";
int port = args.length > 1 ? Integer.parseInt(args[1]) : 6666;
String addr = args.length > 2 ? args[2] : "tcpdv090";
String productKey = args.length > 3 ? args[3] : "ZGxatJ7jhJGCM8J5";
int intervalSec = args.length > 4 ? Integer.parseInt(args[4]) : 5;
String mode = args.length > 5 ? args[5] : "both";
try (Socket socket = new Socket(host, port)) {
socket.setSoTimeout(2000);
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
// 模拟注册
byte[] registerPayload = productKey.getBytes(StandardCharsets.UTF_8);
byte[] registerPacket = encode(addr, DataPackage.CODE_REGISTER, (short) 1, registerPayload);
// 二进制转十六进制
String hexString1 = HexUtil.toHexString(registerPacket);
out.write(registerPacket);
out.flush();
try {
byte[] regAck = readPacket(in);
int regStatus = readStatus(regAck);
System.out.println("register ack status=" + regStatus);
} catch (Exception e) {
System.err.println("注册回复读取失败(服务端可能未回包或连接已断开): " + e.getMessage());
}
// 模拟心跳上报
byte[] heartbeatPacket = encode(addr, DataPackage.CODE_HEARTBEAT, (short) 2, new byte[0]);
out.write(heartbeatPacket);
out.flush();
int mid = 3;
boolean toggle = true;
while (true) {
// 模拟属性上报
if ("prop".equalsIgnoreCase(mode) || ("both".equalsIgnoreCase(mode) && toggle)) {
String propJson = "{\"model\":" + (20 + Math.round(Math.random() * 100) / 10.0) + ",\"remain\":" + (50 + (int) (Math.random() * 20)) + "}";
byte[] propPacket = encode(addr, DataPackage.CODE_DATA_UP, (short) mid, propJson.getBytes(StandardCharsets.UTF_8));
// 二进制转十六进制
String hexString2 = HexUtil.toHexString(propPacket);
out.write(propPacket);
out.flush();
} else {
// 模拟事件上报
String evtJson = "{\"event\":\"alarm\",\"level\":" + (1 + (int) (Math.random() * 3)) + "}";
byte[] evtPacket = encode(addr, DataPackage.CODE_EVENT_UP, (short) mid, evtJson.getBytes(StandardCharsets.UTF_8));
out.write(evtPacket);
out.flush();
}
mid = (mid + 1) & 0xFFFF;
try {
socket.setSoTimeout(500);
byte[] down = readPacket(in);
short downCode = readCode(down);
// 指令下发
if (downCode == DataPackage.CODE_DATA_DOWN) {
String downPayload = new String(readPayload(down), StandardCharsets.UTF_8);
System.out.println("property down received payload=" + downPayload);
}
} catch (Exception ignore) {
} finally {
socket.setSoTimeout(2000);
}
toggle = !toggle;
Thread.sleep(intervalSec * 1000L);
}
}
}
}
2、Netassistant模拟tcp设备




3、属性上报成功



浙公网安备 33010602011771号