1.功能描述
概述:
使用UDP主播方式接收数据,将接收到的消息对数据库进行更改 与 存入缓冲。
具体逻辑:
1.从数据库中读取接收设备的ip和端口等信息
2.根据设备数量建立监听
3.在每个监听对象建立一个计时器,超过设定时间没监听到数据,将当前监听设备设置为离线状态
2.辅助工具类
主要用途是作为主类中的属性,使得能在静态方法中使用mapper中的方法访问数据库
import com.maphao.windfarms.radar.mapper.ManageRadarConfigMapper;
import lombok.Data;
import org.springframework.data.redis.core.RedisTemplate;
/**
* @Author: fxp
* @Date: 2024/4/11 11:31
* @Description
*/
@Data
public class ManageRadarConfigUtil {
private ManageRadarConfigMapper mapper;
private RedisTemplate objRedisTemplate;
}
3.主程序
package com.maphao.windfarms.radar.client;
import com.alibaba.fastjson.JSONObject;
import com.maohao.common.config.RedisCacheContent;
import com.maphao.windfarms.data.dto.equipment.EquipmentStateDto;
import com.maphao.windfarms.data.dto.radar.RadarClientDto;
import com.maphao.windfarms.data.dto.radar.RadarStatusMessage;
import com.maphao.windfarms.radar.mapper.ManageRadarConfigMapper;
import com.maphao.windfarms.radar.util.ManageRadarConfigUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* @Author: fxp
* @Date: 2024/4/11 10:42
* @Description
*/
@Slf4j
@Component
public class RadarClient{
@Resource
private ManageRadarConfigMapper mapper;
@Resource(name="objectRedisTemplate")
private RedisTemplate objRedisTemplate;
private static ManageRadarConfigUtil manageRadarConfigUtil;
// 计时器计数规则,超过当前值,值方法并重制计时器
private static final int TIMEOUT_DURATION = 60; // 1分钟,单位:秒
// 计时器线程
private static Map<Integer,ScheduledExecutorService> mapTimer = new HashMap<>();
// 监听线程
private static List<Thread> ts = new ArrayList<>();
@PostConstruct
public void init(){
log.info("===========初始化=========");
manageRadarConfigUtil = new ManageRadarConfigUtil();
manageRadarConfigUtil.setMapper(this.mapper);
manageRadarConfigUtil.setObjRedisTemplate(this.objRedisTemplate);
run();
}
public void run(){
log.info("=============执行run方法============");
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
// 定义要执行的任务
Runnable task = () -> {
log.info("=================执行任务===================");
// 停止并删除线程
if (!ts.isEmpty()) {
log.info("==================停止并删除监听线程==================");
Iterator<Thread> iterator = ts.iterator();
while (iterator.hasNext()) {
Thread t = iterator.next();
// 判断线程是否需要停止
t.interrupt(); // 停止线程
iterator.remove(); // 删除线程
}
}
// 停止并删除计时器
if (!mapTimer.isEmpty()){
log.info("==================停止并删除计时器==================");
Iterator<Map.Entry<Integer, ScheduledExecutorService>> iterator = mapTimer.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, ScheduledExecutorService> entry = iterator.next();
int id = entry.getKey();
stopAndRemoveTimer(id);
}
}
List<RadarClientDto> dtos = manageRadarConfigUtil.getMapper().selectIpAndPort();
if (null != dtos){
for (RadarClientDto dto : dtos) {
log.info("====================加入监听线程====================");
Thread t = new Thread(new Task(dto));
ts.add(t);
}
}
if (ts.size() > 0){
for (Thread t : ts) {
t.start();
}
}
};
// 每隔5分钟执行一次任务
executor.scheduleAtFixedRate(task, 0, 5, TimeUnit.MINUTES);
}
// 定义一个任务类,实现 Runnable 接口
private static class Task implements Runnable {
private final Integer pid;
private final String ip;
private final Integer port;
private final String code;
public Task(RadarClientDto dto) {
this.pid = dto.getPid();
this.ip = dto.getIp();
this.port = dto.getPort();
this.code = dto.getCode();
}
@Override
public void run() {
// 执行任务的逻辑
log.info("pid = {},ip = {},port = {},code = {},》》》》》开始监听》》》》》",pid,ip,port,code);
RadarClient.monitoring(pid,ip,port,code);
}
}
private static void monitoring(Integer pid,String ip,Integer port,String code){
startTimer(pid);
try {
// 指定组播地址和端口号
InetAddress group = InetAddress.getByName(ip);
// 创建 MulticastSocket 实例并加入组播组
MulticastSocket multicastSocket = new MulticastSocket(port);
multicastSocket.joinGroup(group);
byte[] buffer = new byte[1024];
while (true) {
log.info("========监听到数据=======");
// 接收数据包
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
multicastSocket.receive(packet);
// 解析数据并打印
String json = new String(packet.getData(), 0, packet.getLength());
log.info("=========数据内容========{}",json);
RadarStatusMessage radarStatusMessage = JSONObject.parseObject(json, RadarStatusMessage.class);
if (null != radarStatusMessage && null != radarStatusMessage.getRadarState()){
manageRadarConfigUtil.getMapper().updateStatus(pid,radarStatusMessage.getRadarState());
if (radarStatusMessage.getRadarState() == 1){
setRedis(code);
}
}else {
manageRadarConfigUtil.getMapper().updateStatus(pid,1);
}
resetTimer(pid);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void setRedis(String code){
log.info("========放入缓存=======");
// 将状态放入redis中
EquipmentStateDto stateDto = new EquipmentStateDto();
stateDto.setCode(code);
stateDto.setName("");
stateDto.setUpdateTime(new Date());
stateDto.setState(1);
manageRadarConfigUtil.getObjRedisTemplate().opsForValue().set(RedisCacheContent.equipmentState+code,
stateDto,RedisCacheContent.videoOffLineTime, TimeUnit.SECONDS);
}
private static void startTimer(Integer pid) {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
mapTimer.put(pid,executorService);
executorService.schedule(() -> {
// 在超时时执行相应的操作
log.info("=========未接收到消息,超时!=========");
manageRadarConfigUtil.getMapper().updateStatus(pid,0);
// 例如:关闭连接或执行其他操作
stopAndRemoveTimer(pid);
// resetTimer(pid);
}, TIMEOUT_DURATION, TimeUnit.SECONDS);
}
private static void resetTimer(Integer pid) {
log.info("===========取消之前的计时器任务并重新启动计时器==========");
stopAndRemoveTimer(pid);
startTimer(pid);
}
public static void stopAndRemoveTimer(int id) {
log.info("=====停止计时器====");
ScheduledExecutorService executorService = mapTimer.get(id);
if (executorService != null) {
// 停止执行器服务
executorService.shutdownNow();
try {
// 等待执行器服务终止
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
// 强制终止
executorService.shutdownNow();
}
} catch (InterruptedException e) {
// 重新中断当前线程
Thread.currentThread().interrupt();
}
// 从映射中移除计时器
mapTimer.remove(id);
log.info("Timer with ID " + id + " stopped and removed.");
} else {
log.info("Timer with ID " + id + " not found.");
}
}
}
4.测试,发送消息
package com.fxp.util;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
/**
* 雷达
* @Author: fxp
* @Date: 2024/4/11 10:32
* @Description
*/
public class LDUtil{
private static final int PORT = 8808;
private static final String MULTICAST_GROUP = "222.190.220.31";
public static void main(String[] args) {
sentMessege();
}
public static void sentMessege(){
try {
// 创建组播套接字
InetAddress group = InetAddress.getByName(MULTICAST_GROUP);
MulticastSocket multicastSocket = new MulticastSocket();
// 服务器状态信息
String statusMessage = "{\n" +
" \"RadarType\": 1,\n" +
" \"RadarState\": 1,\n" +
" \"PRFCode\": 2,\n" +
" \"AntennaSpeed\": null,\n" +
" \"Temperature\": null\n" +
"}";
// 发送状态信息
DatagramPacket packet = new DatagramPacket(statusMessage.getBytes(), statusMessage.length(), group, PORT);
multicastSocket.send(packet);
// 关闭套接字
multicastSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}