#修改远程遥控控制方式 将左右轮速改成线速度和角速度

This commit is contained in:
2026-10-16 09:19:31 +08:00
parent 11984316d4
commit 9e3ec6a1dd
11 changed files with 249 additions and 89 deletions

View File

@@ -1,19 +1,19 @@
package com.maibu.constant;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.enums.ConnectionCloseReason;
import io.netty.util.AttributeKey;
import lombok.Data;
import java.util.concurrent.CompletableFuture;
@Data
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.enums.ConnectionCloseReason;
import io.netty.util.AttributeKey;
public class Constant {
public static final AttributeKey<String> ATT_DEVICE_ID = AttributeKey.valueOf("deviceId");
public static final AttributeKey<CompletableFuture<DeviceRunParam>> READ_CONFIG_KEY =
AttributeKey.valueOf("READ_CONFIG");
public static final AttributeKey<CompletableFuture<DeviceRunParam>> READ_CONFIG_KEY = AttributeKey
.valueOf("READ_CONFIG");
public static final AttributeKey<ConnectionCloseReason> ATT_CLOSE_REASON = AttributeKey.valueOf("closeReason");
@@ -27,5 +27,10 @@ public class Constant {
public static final String mqttHandleKey = "hostHandle";
public static final Long hostOfflineInterval = 10000L; //单位毫秒
public static final Long hostOfflineInterval = 10000L; // 单位毫秒
// ==================== 远程控制 ====================
public static final String protocol_version = "1.4.3";
public static final String remote_control_msg_prefix = "remote-msg";
public static final String remote_control_cmd_prefix = "remote-cmd";
}

View File

@@ -1,4 +1,4 @@
package com.maibu.dto;
package com.maibu.core.business;
import lombok.Data;
@@ -42,13 +42,13 @@ public class LawnMoverProtocolEntity {
}
public byte[] toBytes() {
ByteBuffer buffer = ByteBuffer.allocate(15);
ByteBuffer buffer = ByteBuffer.allocate(27);
buffer.order(ByteOrder.LITTLE_ENDIAN); // 根据协议决定字节序
buffer.put(Header1);
buffer.put(Header2);
buffer.put(CommandType);
buffer.putShort(LeftWheelSpeed);
buffer.putShort(RightWheelSpeed);
buffer.putDouble(linearSpeed);
buffer.putDouble(angularSpeed);
buffer.put(ChassisLiftFlag);
buffer.put(MowerSpeedFlag);
buffer.put(IgnitionFlag);
@@ -67,7 +67,46 @@ public class LawnMoverProtocolEntity {
return sb.toString().trim();
}
/**
* 将控制指令字节数组解析为实体对象
*/
public static LawnMoverProtocolEntity parseControlCommand(byte[] data) {
if (data == null || data.length != 27) {
throw new IllegalArgumentException("控制指令长度必须为15字节");
}
ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.order(ByteOrder.LITTLE_ENDIAN);
LawnMoverProtocolEntity entity = new LawnMoverProtocolEntity();
// 帧头
entity.setHeader1(buffer.get());
entity.setHeader2(buffer.get());
// 命令类型
entity.setCommandType(buffer.get());
// 左右轮速度:int16
entity.setLinearSpeed(buffer.getDouble());
entity.setAngularSpeed(buffer.getDouble());
// 控制标志:uint8
entity.setChassisLiftFlag(buffer.get());
entity.setMowerSpeedFlag(buffer.get());
entity.setIgnitionFlag(buffer.get());
entity.setEmergencyStopFlag(buffer.get());
// 预留字段
buffer.get();
buffer.get();
// 帧尾
entity.setEndFlag1(buffer.get());
entity.setEndFlag2(buffer.get());
return entity;
}
// 包头起始字节1
private byte Header1;
@@ -79,6 +118,10 @@ public class LawnMoverProtocolEntity {
private short LeftWheelSpeed;
// 右轮速度:16位有符号
private short RightWheelSpeed;
private double linearSpeed;
private double angularSpeed;
// 底盘升降标志位
private byte ChassisLiftFlag;
// 割刀速度标志位

View File

@@ -1,6 +1,7 @@
package com.maibu.core.business.device;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.maibu.constant.Constant;
import com.maibu.core.business.*;
import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.business.path.RoutePlanSendEntity;
@@ -148,7 +149,7 @@ public class NettyDevice extends Connector {
dto.setMode(workRecord.getMode());
dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis());
dto.setProtocol_version("1.4");
dto.setProtocol_version(Constant.protocol_version);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()),
@@ -361,7 +362,7 @@ public class NettyDevice extends Connector {
dto.setMode(workRecord.getMode());
dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis());
dto.setProtocol_version("1.4");
dto.setProtocol_version(Constant.protocol_version);
PointEntity point = new PointEntity();
if (!StringUtils.isEmpty(workRecord.getMode())) {

View File

@@ -0,0 +1,15 @@
package com.maibu.core.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 上位机远程控制参数
* DeviceRemoteControlDTO
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class DeviceRemoteControlDTO extends HostBase {
private String command_id;
private ParamDetail data;
}

View File

@@ -0,0 +1,18 @@
package com.maibu.core.host;
import lombok.Data;
@Data
public class ParamDetail {
private short left_wheel_rpm; // 左轮转速
private short right_wheel_rpm; // 右轮转速
private double linear_speed; // 线速度
private double angular_speed; // 角速度
private int chassis_lift; // 底盘升降 0:停止 1:升 2:降
private int cutter; // 割刀加减速 0:停止 1:加速 2:减速
private int ignition; // 点火熄火 0:停止 1:点火 2:熄火
private int emergency_stop; // 急停 0:正常 1:急停
private int valid_for_ms; // 指令有效时间,单位毫秒
}

View File

@@ -45,7 +45,7 @@ public class MqttTopic {
// ==================== 远程控制 ====================
/** 远程控制指令下发:前进/后退/转向/割草等(平台->设备),对应 TCP 0x00 remoteControl */
public static final String MOWER_CONTROL_SET = "mower/%s/action/control/set";
public static final String MOWER_CONTROL_SET = "mower/%s/control/remote/set";
// ==================== 任务管理 ====================
/** 路径规划下发(平台->设备),对应 TCP 0x01 path */

View File

@@ -116,7 +116,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 过滤请求
.authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/iot/host/upload-path-csv","/api/thermal/**","/iotDA/device/**", "/websocket/allMemory", "/iot/UAV/**", "/iot/api/**", "/iot/device/userDevice", "/external/sms/sendAliSmsCode", "/login", "/register", "/captchaImage", "/iot/tool/register", "/iot/tool/ntp",
.antMatchers("/system/param/list","/iot/host/upload-path-csv","/api/thermal/**","/iotDA/device/**", "/websocket/allMemory", "/iot/UAV/**", "/iot/api/**", "/iot/device/userDevice", "/external/sms/sendAliSmsCode", "/login", "/register", "/captchaImage", "/iot/tool/register", "/iot/tool/ntp",
"/iot/tool/mqtt/auth", "/iot/workRecord/**", "/iot/tool/mqtt/authv5", "/iot/tool/mqtt/webhook", "/iot/tool/mqtt/webhookv5", "/auth/**/**",
"/wechat/mobileLogin", "/wechat/miniLogin", "/wechat/wxBind/callback").permitAll()
.antMatchers("/zlmhook/**").permitAll()

View File

@@ -1,11 +1,15 @@
package com.maibu.netty.handler;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Set;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.memory.GlobalMemory;
import com.maibu.mqtt.MqttTopic;
import com.maibu.utils.json.JsonUtils;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,9 +19,13 @@ import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.maibu.constant.CommandConstant;
import com.maibu.constant.Constant;
import com.maibu.core.business.LawnMoverProtocolEntity;
import com.maibu.core.business.device.Connector;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.enums.ConnectorType;
import com.maibu.core.host.DeviceRemoteControlDTO;
import com.maibu.core.host.ParamDetail;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
@@ -29,7 +37,6 @@ import io.netty.channel.SimpleChannelInboundHandler;
@ChannelHandler.Sharable
public class CommandForwardHandler extends SimpleChannelInboundHandler<String> {
private static final Logger logger = LoggerFactory.getLogger(CommandForwardHandler.class);
@Autowired
@@ -44,12 +51,11 @@ public class CommandForwardHandler extends SimpleChannelInboundHandler<String> {
byte[] bytes = Hex.decodeHex(msg.toCharArray());
if (bytes.length > 3 && (bytes[2] == CommandConstant.remoteControl
|| bytes[2] == CommandConstant.path
|| bytes[2] == CommandConstant.status
)) {
|| bytes[2] == CommandConstant.status)) {
String senderDeviceId = deviceSessionManager.getDeviceIdByChannel(currentChannel);
NettyDevice senderNettyDevice =
senderDeviceId != null ? deviceSessionManager.getDevice(senderDeviceId) : null;
NettyDevice senderNettyDevice = senderDeviceId != null ? deviceSessionManager.getDevice(senderDeviceId)
: null;
if (senderNettyDevice == null) {
logger.debug("发送拒绝,设备:{}未发送上线指令", senderDeviceId);
@@ -76,22 +82,73 @@ public class CommandForwardHandler extends SimpleChannelInboundHandler<String> {
return;
}
for (Connector target : connectedDevices) {
if (!target.isOnline()) {
logger.debug("发送拒绝master:{},消息到达的salve设备:{},已离线", senderDeviceId, target.getConnectorId());
continue;
}
if (!target.canReceive()) {
logger.debug("发送拒绝master:{},消息到达的slave设备:{},处于禁止接收状态", senderDeviceId, target.getConnectorId());
continue;
}
// todo 向上位机发送控制消息
NettyDevice targetDevice = deviceSessionManager.getDevice(target.getConnectorId());
if (targetDevice == null)
continue;
// 区分有上位机的还有无上位机的 有上位机的通过上位机下发 没有上位机的按照原来的方式下发
if (targetDevice.getDevice().getHasHost()) {
if (bytes[2] == CommandConstant.remoteControl) {
// todo 转换 原先的报文重新组装成上位机的报文格式
DeviceRemoteControlDTO deviceRemoteControlDTO = new DeviceRemoteControlDTO();
LawnMoverProtocolEntity pEntity = LawnMoverProtocolEntity.parseControlCommand(bytes);
if (pEntity != null) {
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.MOWER_CONTROL_SET, target.getConnectorId()), msg);
// Channel targetChannel = target.getChannel();
// if (targetChannel != null && targetChannel.isActive()) {
// targetChannel.writeAndFlush(msg);
// logger.debug("从master:{},向slave:{}, 转发消息:{}", senderDeviceId, target.getConnectorId(), msg);
// }
ParamDetail data = new ParamDetail();
// data.setLeft_wheel_rpm(pEntity.getLeftWheelSpeed());
// data.setRight_wheel_rpm(pEntity.getRightWheelSpeed());
double angularSpeed = BigDecimal.valueOf(pEntity.getAngularSpeed())
.setScale(2, RoundingMode.HALF_UP)
.doubleValue();
double linearSpeed = BigDecimal.valueOf(pEntity.getLinearSpeed())
.setScale(2, RoundingMode.HALF_UP)
.doubleValue();
data.setLinear_speed(linearSpeed);
data.setAngular_speed(angularSpeed);
data.setChassis_lift(pEntity.getChassisLiftFlag());
data.setCutter(pEntity.getMowerSpeedFlag());
data.setIgnition(pEntity.getIgnitionFlag());
data.setEmergency_stop(pEntity.getEmergencyStopFlag());
data.setValid_for_ms(500);
deviceRemoteControlDTO.setData(data);
deviceRemoteControlDTO
.setCommand_id(Constant.remote_control_cmd_prefix + System.currentTimeMillis());
deviceRemoteControlDTO.setSn(target.getConnectorId());
deviceRemoteControlDTO.setTimestamp(System.currentTimeMillis());
deviceRemoteControlDTO
.setMessage_id(Constant.remote_control_msg_prefix + System.currentTimeMillis());
deviceRemoteControlDTO.setProtocol_version(Constant.protocol_version);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_CONTROL_SET, target.getConnectorId()),
JsonUtils.toJsonString(deviceRemoteControlDTO));
logger.debug("master:{},向slave:{} 有上位机, 转发遥控指令:{}", senderDeviceId,
target.getConnectorId(),
JsonUtils.toJsonString(deviceRemoteControlDTO));
}
}
} else {
if (!target.isOnline()) {
logger.debug("发送拒绝master:{},消息到达的salve设备:{},已离线", senderDeviceId,
target.getConnectorId());
continue;
}
Channel targetChannel = target.getChannel();
if (targetChannel != null && targetChannel.isActive()) {
targetChannel.writeAndFlush(msg);
logger.debug("从master:{},向slave:{} 无上位机, 转发消息:{}", senderDeviceId,
target.getConnectorId(), msg);
}
}
}
} else if (ConnectorType.SLAVE.equals(senderNettyDevice.getDeviceType())) {
List<NettyDevice> masters = deviceSessionManager.getMastersBySlaveId(senderDeviceId);

View File

@@ -1,9 +1,12 @@
package com.maibu.control;
import lombok.Data;
@Data
public class DiffSteer {
public static final int Polarity_High = 0; //0
public static final int Polarity_Low = 0; //1
public static final int Polarity_High = 0; // 0
public static final int Polarity_Low = 0; // 1
private float turnSpeedScale;
private float forwardSpeedScale;
@@ -15,6 +18,9 @@ public class DiffSteer {
private int leftWheelSpeed;
private int rightWheelSpeed;
private double linearSpeed;
private double angularSpeed;
public int getLeftWheelSpeed() {
return leftWheelSpeed;
}
@@ -63,6 +69,14 @@ public class DiffSteer {
rightWheelSpeed = clamp(rightWheelSpeed, -speedAmplLimit, speedAmplLimit);
}
// 计算线速度和轮速度
public void calcLinearAngularSpeed(int x, int y, int maxLinear, int maxAngular) {
this.linearSpeed = y * maxLinear / 1000.0;
this.angularSpeed = x * maxAngular / 1000.0;
}
// 设置前向速比
public void setTurnSpeedScale(int turnSpeedMax, int xMax) {
this.turnSpeedScale = (float) turnSpeedMax / (float) xMax;
@@ -88,5 +102,4 @@ public class DiffSteer {
return (val < min) ? min : ((val > max) ? max : val);
}
}

View File

@@ -1,9 +1,8 @@
package com.maibu.utils;
import com.maibu.common.MiddleCommandConstant;
import com.maibu.control.DiffSteer;
import com.maibu.dto.LawnMoverProtocolEntity;
import com.maibu.core.business.LawnMoverProtocolEntity;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -11,24 +10,29 @@ import java.util.List;
public class ControlUtils {
public static LawnMoverProtocolEntity getCarControlMessage(DiffSteer diffSteer, int originX, int originY, List<Boolean> buttons) {
public static LawnMoverProtocolEntity getCarControlMessage(DiffSteer diffSteer, int originX, int originY,
List<Boolean> buttons, int maxLinear, int maxAngular) {
LawnMoverProtocolEntity state = new LawnMoverProtocolEntity();
diffSteer.calcWheelSpeed(originX, originY);
diffSteer.calcLinearAngularSpeed(originX, originY, maxLinear, maxAngular);
state.setCommandType(MiddleCommandConstant.remoteControl);
state.setLeftWheelSpeed((short) diffSteer.getLeftWheelSpeed());
state.setRightWheelSpeed((short) diffSteer.getRightWheelSpeed());
//对应的 button数组 L1 button【4】 R1 button【5】 A对应的button【0】 B对应button【1】 X对应button【2】 Y对应button【3】 button[7]急停
//A升B降底盘 X割刀加速Y减速 L1点火 R1熄火
state.setLinearSpeed(diffSteer.getLinearSpeed());
state.setAngularSpeed(diffSteer.getAngularSpeed());
// 对应的 button数组 L1 button【4】 R1 button【5】 A对应的button【0】 B对应button【1】
// X对应button【2】 Y对应button【3】 button[7]急停
// A升B降底盘 X割刀加速Y减速 L1点火 R1熄火
Boolean A = buttons.get(0);
Boolean B = buttons.get(1);
Boolean X = buttons.get(2);
Boolean Y = buttons.get(3);
Boolean L1 = buttons.get(4);
Boolean R1 = buttons.get(5);
Boolean eStop = buttons.get(8); //急停
//底盘升降
Boolean eStop = buttons.get(8); // 急停
// 底盘升降
int chassisLiftFlag = 0;
if (A & !B) {
chassisLiftFlag = 1;
@@ -36,7 +40,7 @@ public class ControlUtils {
chassisLiftFlag = 2;
}
state.setChassisLiftFlag((byte) chassisLiftFlag);
//割刀加减速
// 割刀加减速
int mowerSpeedFlag = 0;
if (X & !Y) {
mowerSpeedFlag = 1;
@@ -44,7 +48,7 @@ public class ControlUtils {
mowerSpeedFlag = 2;
}
state.setMowerSpeedFlag((byte) mowerSpeedFlag);
//点火熄火
// 点火熄火
int ignitionFlag = 0;
if (L1 & !R1) {
ignitionFlag = 1;
@@ -55,26 +59,29 @@ public class ControlUtils {
int emergencyStopFlag = eStop ? 1 : 0;
state.setEmergencyStopFlag((byte) emergencyStopFlag);
// val toBytes = state.toBytes()
// println("toBytes==" + LawnMoverProtocolEntity.printBytesToHex(toBytes))
// val toBytes = state.toBytes()
// println("toBytes==" + LawnMoverProtocolEntity.printBytesToHex(toBytes))
return state;
}
public static byte[] buildControlCommand(LawnMoverProtocolEntity entity) {
ByteBuffer buffer = ByteBuffer.allocate(15);
ByteBuffer buffer = ByteBuffer.allocate(27);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put(entity.getHeader1());
buffer.put(entity.getHeader2());
buffer.put(entity.getCommandType());
buffer.putShort(entity.getLeftWheelSpeed());//左轮速度
buffer.putShort(entity.getRightWheelSpeed());//右轮速度
// buffer.putShort(entity.getLeftWheelSpeed());//左轮速度
// buffer.putShort(entity.getRightWheelSpeed());//右轮速度
buffer.put(entity.getChassisLiftFlag());//底盘升降
buffer.put(entity.getMowerSpeedFlag());//割刀加减速
buffer.put(entity.getIgnitionFlag());//点火状态
buffer.put(entity.getEmergencyStopFlag());//急停
buffer.putDouble(entity.getAngularSpeed());// 左轮速度
buffer.putDouble(entity.getLinearSpeed());// 右轮速度
buffer.put(entity.getChassisLiftFlag());// 底盘升降
buffer.put(entity.getMowerSpeedFlag());// 割刀加减速
buffer.put(entity.getIgnitionFlag());// 点火状态
buffer.put(entity.getEmergencyStopFlag());// 急停
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);

View File

@@ -2,6 +2,7 @@ package com.maibu.websocket;
import com.maibu.constant.CommandConstant;
import com.maibu.common.MiddleConstant;
import com.maibu.core.business.LawnMoverProtocolEntity;
import com.maibu.core.enums.CommandRequestType;
import com.maibu.core.enums.MesType;
import com.maibu.dto.*;
@@ -36,7 +37,6 @@ import java.util.concurrent.TimeUnit;
public class WebsocketHandler extends WebSocketServer {
private static final Logger logger = LoggerFactory.getLogger(WebsocketHandler.class);
// 存储客户端连接:key=WebSocket连接对象,value=最后一次活跃时间(毫秒)
private final Map<WebSocket, Long> clientActiveTimeMap = new ConcurrentHashMap<>();
// 空闲超时时间(10秒):超过10秒无消息则判定为断开
@@ -44,17 +44,17 @@ public class WebsocketHandler extends WebSocketServer {
// 定时检测线程池(每隔10秒检测一次空闲连接)
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
public WebsocketHandler(int port) {
super(new InetSocketAddress(port));
// 启动空闲连接检测任务
// startIdleCheckTask();
// startIdleCheckTask();
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
logger.info("客户端连接成功: remoteAddress={}, 当前在线数: {}", conn.getRemoteSocketAddress(), MiddleGlobalMemory.onlineSockets.size());
logger.info("客户端连接成功: remoteAddress={}, 当前在线数: {}", conn.getRemoteSocketAddress(),
MiddleGlobalMemory.onlineSockets.size());
}
@Override
@@ -62,7 +62,8 @@ public class WebsocketHandler extends WebSocketServer {
String key = MiddleGlobalMemory.findBySocket(conn);
if (key != null) {
releaseResource(key);
logger.info("客户端断开连接: remoteAddress={}, code={}, reason={}, 当前在线数: {}", conn.getRemoteSocketAddress(), code, reason, MiddleGlobalMemory.onlineSockets.size());
logger.info("客户端断开连接: remoteAddress={}, code={}, reason={}, 当前在线数: {}", conn.getRemoteSocketAddress(), code,
reason, MiddleGlobalMemory.onlineSockets.size());
}
MiddleGlobalMemory.removeByWebSocket(conn);
}
@@ -100,32 +101,34 @@ public class WebsocketHandler extends WebSocketServer {
client.initConnect(MiddleConstant.vertxIp, 9001);
}
} else if (MesType.path.equals(type)) {
//todo下发路径 预留
// todo下发路径 预留
pathDistribute();
} else if (MesType.remoteControl.equals(type)) {
//遥控
// 遥控
RemoteData remoteData = webMessageBaseDTO.getRemoteData();
if (remoteData != null) {
List<Double> axes = remoteData.getAxes();
List<Boolean> buttons = remoteData.getButtons();
Double y = axes.get(1) * 1000 * -1; //前后值反了
Double y = axes.get(1) * 1000 * -1; // 前后值反了
Double x = axes.get(2) * 1000;
int intX = (int) x.doubleValue();
int intY = (int) y.doubleValue();
// todo 计算线速度和角速度 还需要根据车型来给线速度 角速度范围最大值
MiddleGlobalMemory.initDiff();
LawnMoverProtocolEntity entity = ControlUtils.getCarControlMessage(MiddleGlobalMemory.diffSteer, intX, intY, buttons);
LawnMoverProtocolEntity entity = ControlUtils.getCarControlMessage(MiddleGlobalMemory.diffSteer,
intX, intY, buttons, 1, 2);
byte[] buf = ControlUtils.buildControlCommand(entity);
logger.debug("Netty客户端:{}发送遥控数据: {}", userName, JsonUtils.toJsonString(entity));
NettyClient nettyClient = MiddleGlobalMemory.nettyClientMap.get(key);
if (nettyClient != null && nettyClient.isConnected()) {
// if (!nettyClient.isConnected()) nettyClient.connect();
// if (!nettyClient.isConnected()) nettyClient.connect();
nettyClient.sendData(buf);
}
}
}
// else if(MesType.heartbeat.equals(type)){
// clientActiveTimeMap.put(conn,System.currentTimeMillis());
// }
// else if(MesType.heartbeat.equals(type)){
// clientActiveTimeMap.put(conn,System.currentTimeMillis());
// }
else if (MesType.switchPermission.equals(type)) {
DeviceRequestDTO requestDTO = new DeviceRequestDTO();
requestDTO.setRequest(CommandRequestType.switch_control);
@@ -138,7 +141,7 @@ public class WebsocketHandler extends WebSocketServer {
ByteBuf buf = Unpooled.buffer();
CommandUtils.buildCommand(buf, requestDTO, CommandConstant.interaction);
if (nettyClient != null && nettyClient.isConnected()) {
// if (!nettyClient.isConnected()) nettyClient.connect();
// if (!nettyClient.isConnected()) nettyClient.connect();
nettyClient.sendData(buf.array());
}
} else if (MesType.switchResult.equals(type)) {
@@ -156,7 +159,7 @@ public class WebsocketHandler extends WebSocketServer {
ByteBuf buf = Unpooled.buffer();
CommandUtils.buildCommand(buf, requestDTO, CommandConstant.interaction);
if (nettyClient != null && nettyClient.isConnected()) {
// if (!nettyClient.isConnected()) nettyClient.connect();
// if (!nettyClient.isConnected()) nettyClient.connect();
nettyClient.sendData(buf.array());
}
}
@@ -186,7 +189,8 @@ public class WebsocketHandler extends WebSocketServer {
@Override
public void onError(WebSocket conn, Exception ex) {
String key = MiddleGlobalMemory.findBySocket(conn);
logger.error("WebSocket错误: clientId={}, remoteAddress={}, error={}", key, conn != null ? conn.getRemoteSocketAddress() : null, ex.getMessage(), ex);
logger.error("WebSocket错误: clientId={}, remoteAddress={}, error={}", key,
conn != null ? conn.getRemoteSocketAddress() : null, ex.getMessage(), ex);
// 发生错误时清理连接
if (key != null) {
releaseResource(key);
@@ -222,7 +226,6 @@ public class WebsocketHandler extends WebSocketServer {
logger.debug("广播消息给所有客户端: message={}, 客户端数量: {}", message, connections.size());
}
// 核心:定时检测空闲连接(每隔10秒执行一次)
private void startIdleCheckTask() {
executor.scheduleAtFixedRate(() -> {
@@ -261,21 +264,21 @@ public class WebsocketHandler extends WebSocketServer {
}
}
}
// clientActiveTimeMap.clear(); // 清空空闲记录
//
// // 2. 关闭定时检测线程池(核心:终止非守护线程)
// if (!idleCheckExecutor.isShutdown()) {
// idleCheckExecutor.shutdownNow(); // 立即关闭线程池
// try {
// // 等待线程池终止,最多等3秒
// if (!idleCheckExecutor.awaitTermination(3, TimeUnit.SECONDS)) {
// logger.warn("空闲检测线程池未正常终止");
// }
// } catch (InterruptedException e) {
// idleCheckExecutor.shutdownNow();
// Thread.currentThread().interrupt();
// }
// }
// clientActiveTimeMap.clear(); // 清空空闲记录
//
// // 2. 关闭定时检测线程池(核心:终止非守护线程)
// if (!idleCheckExecutor.isShutdown()) {
// idleCheckExecutor.shutdownNow(); // 立即关闭线程池
// try {
// // 等待线程池终止,最多等3秒
// if (!idleCheckExecutor.awaitTermination(3, TimeUnit.SECONDS)) {
// logger.warn("空闲检测线程池未正常终止");
// }
// } catch (InterruptedException e) {
// idleCheckExecutor.shutdownNow();
// Thread.currentThread().interrupt();
// }
// }
// 3. 批量关闭所有Netty客户端连接
for (NettyClient client : MiddleGlobalMemory.nettyClientMap.values()) {
@@ -300,5 +303,3 @@ public class WebsocketHandler extends WebSocketServer {
}
}
}