|
|
@ -20,9 +20,9 @@ public class CsdjClientSimulator { |
|
|
// 配置
|
|
|
// 配置
|
|
|
private static final String SERVER_HOST = "127.0.0.1"; |
|
|
private static final String SERVER_HOST = "127.0.0.1"; |
|
|
private static final int SERVER_PORT = 7114; |
|
|
private static final int SERVER_PORT = 7114; |
|
|
private static final String TERMINAL_ID = "TEST001"; |
|
|
private static final String TERMINAL_ID = "TEST002"; |
|
|
private static final String USER_ID = "csdj"; |
|
|
private static final String USER_ID = "user11"; |
|
|
private static final String PASSWORD = "csdj"; |
|
|
private static final String PASSWORD = "pwd1"; |
|
|
|
|
|
|
|
|
// 帧类型定义
|
|
|
// 帧类型定义
|
|
|
private static final byte FRAME_ID_PASSWORD = (byte) 0xC1; |
|
|
private static final byte FRAME_ID_PASSWORD = (byte) 0xC1; |
|
|
@ -35,90 +35,173 @@ public class CsdjClientSimulator { |
|
|
|
|
|
|
|
|
// 状态机
|
|
|
// 状态机
|
|
|
private enum State { |
|
|
private enum State { |
|
|
WAIT_IDPWD, WAIT_NMSR1, WAIT_RR, WAIT_DISC, FINISHED |
|
|
WAIT_IDPWD, |
|
|
|
|
|
WAIT_NMSR1, |
|
|
|
|
|
WAIT_RR, |
|
|
|
|
|
WAIT_DISC, |
|
|
|
|
|
WAIT_SERVER_CLOSE, |
|
|
|
|
|
FINISHED |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public static void main(String[] args) throws InterruptedException { |
|
|
public static void main(String[] args) throws InterruptedException { |
|
|
log.info("CSDJ设备模拟器启动..."); |
|
|
log.info("CSDJ设备模拟器启动..."); |
|
|
log.info("连接服务器: {}:{}", SERVER_HOST, SERVER_PORT); |
|
|
log.info("连接服务器: {}:{}", SERVER_HOST, SERVER_PORT); |
|
|
|
|
|
|
|
|
try (Socket socket = new Socket(SERVER_HOST, SERVER_PORT)) { |
|
|
Socket socket = null; |
|
|
|
|
|
try { |
|
|
|
|
|
socket = new Socket(SERVER_HOST, SERVER_PORT); |
|
|
log.info("连接成功!"); |
|
|
log.info("连接成功!"); |
|
|
|
|
|
|
|
|
InputStream input = socket.getInputStream(); |
|
|
InputStream input = socket.getInputStream(); |
|
|
OutputStream output = socket.getOutputStream(); |
|
|
OutputStream output = socket.getOutputStream(); |
|
|
|
|
|
|
|
|
State state = State.WAIT_IDPWD; |
|
|
State state = State.WAIT_IDPWD; |
|
|
|
|
|
int authAttemptCount = 0; |
|
|
|
|
|
|
|
|
|
|
|
while (state != State.FINISHED && !socket.isClosed()) { |
|
|
|
|
|
switch (state) { |
|
|
|
|
|
case WAIT_IDPWD: |
|
|
|
|
|
// ========== 步骤1: 等待 IDPWD ==========
|
|
|
|
|
|
log.info("---------- 步骤1: 等待 IDPWD ----------"); |
|
|
|
|
|
CsdjFrame idpwdFrame = expectFrame(input, FRAME_ID_PASSWORD); |
|
|
|
|
|
log.info("✅ 收到: IDPWD (0xC1)"); |
|
|
|
|
|
logFrame(idpwdFrame); |
|
|
|
|
|
state = State.WAIT_NMSR1; |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤2: 发送 IDPWD-UA ==========
|
|
|
|
|
|
log.info("---------- 步骤2: 发送 IDPWD-UA ----------"); |
|
|
|
|
|
CsdjFrame idpwdUaFrame = createIdpwdUaFrame(USER_ID, PASSWORD); |
|
|
|
|
|
sendFrame(output, idpwdUaFrame); |
|
|
|
|
|
log.info("✅ 已发送: IDPWD-UA (0xC2)"); |
|
|
|
|
|
logFrame(idpwdUaFrame); |
|
|
|
|
|
authAttemptCount++; |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case WAIT_NMSR1: |
|
|
|
|
|
// ========== 步骤3: 等待 NMSR 或者 IDPWD(重发) 或者 DISC ==========
|
|
|
|
|
|
log.info("---------- 步骤3: 等待 NMSR 或 IDPWD 或 DISC ----------"); |
|
|
|
|
|
// 先读取帧,再判断类型
|
|
|
|
|
|
CsdjFrame frame = readFrame(input); |
|
|
|
|
|
|
|
|
|
|
|
if (frame.controlId == FRAME_NEW_MESSAGE_SEND_READY) { |
|
|
|
|
|
// 收到 NMSR,认证成功,继续正常流程
|
|
|
|
|
|
log.info("✅ 收到: NMSR (0xC3) - 认证成功"); |
|
|
|
|
|
logFrame(frame); |
|
|
|
|
|
state = State.WAIT_RR; |
|
|
|
|
|
continueNormalFlow(input, output, socket); |
|
|
|
|
|
state = State.WAIT_SERVER_CLOSE; |
|
|
|
|
|
} else if (frame.controlId == FRAME_ID_PASSWORD) { |
|
|
|
|
|
// 收到 IDPWD,服务器在重发认证请求,我们也要重发 IDPWD-UA
|
|
|
|
|
|
log.info("🔄 收到: IDPWD (0xC1) - 服务器在重发认证请求 (attempt {})", authAttemptCount); |
|
|
|
|
|
logFrame(frame); |
|
|
|
|
|
log.info("---------- 重发 IDPWD-UA ----------"); |
|
|
|
|
|
CsdjFrame idpwdUaFrame2 = createIdpwdUaFrame(USER_ID, PASSWORD); |
|
|
|
|
|
sendFrame(output, idpwdUaFrame2); |
|
|
|
|
|
log.info("✅ 已重发: IDPWD-UA (0xC2)"); |
|
|
|
|
|
logFrame(idpwdUaFrame2); |
|
|
|
|
|
authAttemptCount++; |
|
|
|
|
|
state = State.WAIT_NMSR1; |
|
|
|
|
|
} else if (frame.controlId == FRAME_DISCONNECT) { |
|
|
|
|
|
// 收到 DISC,服务器要断开
|
|
|
|
|
|
log.info("❌ 收到: DISC (0xC4) - 服务器要断开连接 (失败 {} 次后)", authAttemptCount); |
|
|
|
|
|
logFrame(frame); |
|
|
|
|
|
log.info("发送 DISC-UA 确认断开"); |
|
|
|
|
|
CsdjFrame discUaFrame = createSimpleFrame(FRAME_DISCONNECT_UA); |
|
|
|
|
|
sendFrame(output, discUaFrame); |
|
|
|
|
|
log.info("✅ 已发送: DISC-UA (0xC5)"); |
|
|
|
|
|
logFrame(discUaFrame); |
|
|
|
|
|
state = State.WAIT_SERVER_CLOSE; |
|
|
|
|
|
} else { |
|
|
|
|
|
String receivedName = getFrameName(frame.controlId); |
|
|
|
|
|
throw new IOException(String.format("❌ 帧类型错误!期望: NMSR/IDPWD/DISC, 实际: %s(0x%02X)", |
|
|
|
|
|
receivedName, frame.controlId & 0xFF)); |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case WAIT_SERVER_CLOSE: |
|
|
|
|
|
// ========== 等待服务器关闭连接 ==========
|
|
|
|
|
|
log.info("---------- 等待服务器关闭连接 ----------"); |
|
|
|
|
|
// 继续读取,直到连接关闭
|
|
|
|
|
|
CsdjFrame waitFrame = readFrame(input); |
|
|
|
|
|
// 如果读到了帧,可能是服务器又发了什么,继续处理
|
|
|
|
|
|
if (waitFrame != null) { |
|
|
|
|
|
log.info("收到帧: {}", getFrameName(waitFrame.controlId)); |
|
|
|
|
|
logFrame(waitFrame); |
|
|
|
|
|
// 如果收到 DISC,再次回复 DISC-UA
|
|
|
|
|
|
if (waitFrame.controlId == FRAME_DISCONNECT) { |
|
|
|
|
|
log.info("发送 DISC-UA 确认断开"); |
|
|
|
|
|
CsdjFrame discUaFrame2 = createSimpleFrame(FRAME_DISCONNECT_UA); |
|
|
|
|
|
sendFrame(output, discUaFrame2); |
|
|
|
|
|
log.info("✅ 已发送: DISC-UA (0xC5)"); |
|
|
|
|
|
logFrame(discUaFrame2); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
|
log.warn("Unknown state: {}", state); |
|
|
|
|
|
state = State.FINISHED; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// ========== 步骤1: 等待 IDPWD ==========
|
|
|
if (state == State.FINISHED) { |
|
|
log.info("---------- 步骤1: 等待 IDPWD ----------"); |
|
|
log.info("========================================"); |
|
|
CsdjFrame idpwdFrame = expectFrame(input, FRAME_ID_PASSWORD); |
|
|
log.info("✅ 流程结束!"); |
|
|
log.info("✅ 收到: IDPWD (0xC1)"); |
|
|
log.info("========================================"); |
|
|
logFrame(idpwdFrame); |
|
|
} |
|
|
state = State.WAIT_NMSR1; |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤2: 发送 IDPWD-UA ==========
|
|
|
|
|
|
log.info("---------- 步骤2: 发送 IDPWD-UA ----------"); |
|
|
|
|
|
CsdjFrame idpwdUaFrame = createIdpwdUaFrame(USER_ID, PASSWORD); |
|
|
|
|
|
sendFrame(output, idpwdUaFrame); |
|
|
|
|
|
log.info("✅ 已发送: IDPWD-UA (0xC2)"); |
|
|
|
|
|
logFrame(idpwdUaFrame); |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤3: 等待 NMSR ==========
|
|
|
|
|
|
log.info("---------- 步骤3: 等待 NMSR ----------"); |
|
|
|
|
|
CsdjFrame nmsrFrame = expectFrame(input, FRAME_NEW_MESSAGE_SEND_READY); |
|
|
|
|
|
log.info("✅ 收到: NMSR (0xC3)"); |
|
|
|
|
|
logFrame(nmsrFrame); |
|
|
|
|
|
state = State.WAIT_RR; |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤4: 发送 I帧(通報数据)==========
|
|
|
|
|
|
log.info("---------- 步骤4: 发送通報数据 ----------"); |
|
|
|
|
|
byte[] sensorData = createMockSensorData(); // 模拟温湿度数据
|
|
|
|
|
|
CsdjFrame iFrame = createInfoFrame(sensorData); |
|
|
|
|
|
sendFrame(output, iFrame); |
|
|
|
|
|
log.info("✅ 已发送: I帧 (0x01)"); |
|
|
|
|
|
logFrame(iFrame); |
|
|
|
|
|
log.info("通報数据: {}", bytesToHex(sensorData)); |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤5: 等待 RR ==========
|
|
|
|
|
|
log.info("---------- 步骤5: 等待 RR ----------"); |
|
|
|
|
|
CsdjFrame rrFrame = expectFrame(input, FRAME_RECEIVE_READY); |
|
|
|
|
|
log.info("✅ 收到: RR (0x81)"); |
|
|
|
|
|
logFrame(rrFrame); |
|
|
|
|
|
state = State.WAIT_DISC; |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤6: 发送 NMSR (我发完了!)==========
|
|
|
|
|
|
log.info("---------- 步骤6: 发送 NMSR ----------"); |
|
|
|
|
|
CsdjFrame nmsrFrame2 = createSimpleFrame(FRAME_NEW_MESSAGE_SEND_READY); |
|
|
|
|
|
sendFrame(output, nmsrFrame2); |
|
|
|
|
|
log.info("✅ 已发送: NMSR (0xC3)"); |
|
|
|
|
|
logFrame(nmsrFrame2); |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤7: 等待 DISC ==========
|
|
|
|
|
|
log.info("---------- 步骤7: 等待 DISC ----------"); |
|
|
|
|
|
CsdjFrame discFrame = expectFrame(input, FRAME_DISCONNECT); |
|
|
|
|
|
log.info("✅ 收到: DISC (0xC4)"); |
|
|
|
|
|
logFrame(discFrame); |
|
|
|
|
|
state = State.FINISHED; |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤8: 发送 DISC-UA ==========
|
|
|
|
|
|
log.info("---------- 步骤8: 发送 DISC-UA ----------"); |
|
|
|
|
|
CsdjFrame discUaFrame = createSimpleFrame(FRAME_DISCONNECT_UA); |
|
|
|
|
|
sendFrame(output, discUaFrame); |
|
|
|
|
|
log.info("✅ 已发送: DISC-UA (0xC5)"); |
|
|
|
|
|
logFrame(discUaFrame); |
|
|
|
|
|
|
|
|
|
|
|
log.info("========================================"); |
|
|
|
|
|
log.info("✅ 通報流程全部完成!"); |
|
|
|
|
|
log.info("========================================"); |
|
|
|
|
|
|
|
|
|
|
|
} catch (IOException e) { |
|
|
} catch (IOException e) { |
|
|
log.error("❌ 连接错误: {}", e.getMessage(), e); |
|
|
log.error("❌ 连接错误: {}", e.getMessage(), e); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TimeUnit.SECONDS.sleep(1); |
|
|
TimeUnit.SECONDS.sleep(1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 正常流程(认证成功后的流程) |
|
|
|
|
|
*/ |
|
|
|
|
|
private static void continueNormalFlow(InputStream input, OutputStream output, Socket socket) throws IOException { |
|
|
|
|
|
State state = State.WAIT_RR; |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤4: 发送 I帧(通報数据)==========
|
|
|
|
|
|
log.info("---------- 步骤4: 发送通報数据 ----------"); |
|
|
|
|
|
byte[] sensorData = createMockSensorData(); |
|
|
|
|
|
CsdjFrame iFrame = createInfoFrame(sensorData); |
|
|
|
|
|
sendFrame(output, iFrame); |
|
|
|
|
|
log.info("✅ 已发送: I帧 (0x01)"); |
|
|
|
|
|
logFrame(iFrame); |
|
|
|
|
|
log.info("通報数据: {}", bytesToHex(sensorData)); |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤5: 等待 RR ==========
|
|
|
|
|
|
log.info("---------- 步骤5: 等待 RR ----------"); |
|
|
|
|
|
CsdjFrame rrFrame = expectFrame(input, FRAME_RECEIVE_READY); |
|
|
|
|
|
log.info("✅ 收到: RR (0x81)"); |
|
|
|
|
|
logFrame(rrFrame); |
|
|
|
|
|
state = State.WAIT_DISC; |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤6: 发送 NMSR ==========
|
|
|
|
|
|
log.info("---------- 步骤6: 发送 NMSR ----------"); |
|
|
|
|
|
CsdjFrame nmsrFrame2 = createSimpleFrame(FRAME_NEW_MESSAGE_SEND_READY); |
|
|
|
|
|
sendFrame(output, nmsrFrame2); |
|
|
|
|
|
log.info("✅ 已发送: NMSR (0xC3)"); |
|
|
|
|
|
logFrame(nmsrFrame2); |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤7: 等待 DISC ==========
|
|
|
|
|
|
log.info("---------- 步骤7: 等待 DISC ----------"); |
|
|
|
|
|
CsdjFrame discFrame = expectFrame(input, FRAME_DISCONNECT); |
|
|
|
|
|
log.info("✅ 收到: DISC (0xC4)"); |
|
|
|
|
|
logFrame(discFrame); |
|
|
|
|
|
|
|
|
|
|
|
// ========== 步骤8: 发送 DISC-UA ==========
|
|
|
|
|
|
log.info("---------- 步骤8: 发送 DISC-UA ----------"); |
|
|
|
|
|
CsdjFrame discUaFrame = createSimpleFrame(FRAME_DISCONNECT_UA); |
|
|
|
|
|
sendFrame(output, discUaFrame); |
|
|
|
|
|
log.info("✅ 已发送: DISC-UA (0xC5)"); |
|
|
|
|
|
logFrame(discUaFrame); |
|
|
|
|
|
|
|
|
|
|
|
// 不设置 FINISHED,让主循环继续等待服务器关闭 socket
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// ==================== 状态机校验帧 ====================
|
|
|
// ==================== 状态机校验帧 ====================
|
|
|
private static CsdjFrame expectFrame(InputStream input, byte expectedFrameId) throws IOException { |
|
|
private static CsdjFrame expectFrame(InputStream input, byte expectedFrameId) throws IOException { |
|
|
CsdjFrame frame = readFrame(input); |
|
|
CsdjFrame frame = readFrame(input); |
|
|
@ -151,8 +234,7 @@ public class CsdjClientSimulator { |
|
|
if (infoLen > 0) { |
|
|
if (infoLen > 0) { |
|
|
info = new byte[infoLen]; |
|
|
info = new byte[infoLen]; |
|
|
readLen = input.read(info); |
|
|
readLen = input.read(info); |
|
|
if (readLen != infoLen) { |
|
|
if (readLen != infoLen) { throw new IOException("读取信息部失败: " + readLen + " != " + infoLen); |
|
|
throw new IOException("读取信息部失败: " + readLen + " != " + infoLen); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|