串口解析的服务器流程优化
介绍
笔者项目中使用purejavacomm实现串口通信,purejavacomm自带线程池以实现COM口的监听,但是当后续数据处理流程过长,线程占用时间过长,会导致监听阻塞,会导致粘包出现。
解决办法
笔者项目中使用redis来做缓存,也就顺便用redis做了消息队列,以实现purejavacomm线程池线程的快速归还,然后再用自定义更大的线程池来实现串口数据的处理。
Redis消息队列实现
@Resource
private JedisPool jedisPool;
@Resource
@Qualifier("taskExecutor")
private Executor taskExecutor;
@Override
public void publishMessage(String channel, String message) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.publish(channel, message);
}catch (Exception e){
e.printStackTrace();
log.error("发布消息异常!" + e);
}
}
// 实现订阅方法
@Override
public void subscribeToChannel(String channel, MessageListener listener) {
taskExecutor.execute(() -> {
try (Jedis jedis = jedisPool.getResource()) {
JedisPubSub pubSub = new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
listener.onMessage(channel, message);
}
};
jedis.subscribe(pubSub, channel);
} catch (Exception e) {
e.printStackTrace();
}
});
}
串口数据解析
CommandLineRunner 是一个非常有用的接口,特别适合在应用启动时执行初始化或监听任务。在代码中,它被用来启动 Redis 消息监听器,确保应用启动后能够立即开始处理来自 Redis 的消息。
@Component
@Slf4j
public class DataHandler implements CommandLineRunner {
// ... 其他代码 ...
@Override
public void run(String... args) throws Exception {
log.info("DataHandler 启动成功!开始监听消息");
redisService.subscribeToChannel(REDIS_QUEUE_NAME, (channel, message) -> {
log.info("DataHandler 收到消息:{}", message);
try {
String[] split = message.split(":");
if (split.length == 2) {
String comNum = split[0];
byte[] readBuffer = ByteUtil.hexToByteArray(split[1], false);
dataHandle(readBuffer, comNum);
}
} catch (Exception e) {
e.printStackTrace();
log.error("DataHandler 处理消息出错:{}", e.getMessage());
}
});
}
}