需求:在springboot项目启动后,另开启一个线程来监听某个端口发送的udp包数据,并且实时将获取到的数据入库。
1.可以先下载一个TCP/UDP Socket调试工具。
因为udp没有response,所以先确定用工具能接收到udp包数据,创建udp server来监听某个端口,创建udp client给指定ip和端口发数据包,联调时候先用此工具看看能否接收到外部发送到本地的udp数据包。
2.如果确定上述工具可以接收到目标数据包,那么可以开始用代码实现了,直接复制即可使用,其中在这里我们开启了一个线程监听发送到本地9072端口的udp数据包。
package com.genew.nms.utils.WebSocket;
import com.genew.nms.bean.BulkCallRecord;
import com.genew.nms.service.bulkcalltask.IBulkCallRecordService;
import com.genew.nms.utils.ApplicationContextUtil;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
* @author Salong
* @date 2022/5/25 11:02
* @Email:salong0503@aliyun.com
*/
@Slf4j
@WebListener
public class UdpClient implements ServletContextListener {
public static final int MAX_UDP_DATA_SIZE = 4096;
public static final int UDP_PORT = 9072;
public static DatagramPacket packet = null;
public static DatagramSocket socket = null;
@Override
public void contextInitialized(ServletContextEvent sce) {
try {
log.info("Start thread to listen to UDP(port:{}) data!" , UDP_PORT );
// 启动一个线程,监听UDP数据报
new Thread(new UDPProcess(UDP_PORT)).start();
} catch (Exception e) {
e.printStackTrace();
}
}
class UDPProcess implements Runnable {
public UDPProcess(final int port) throws SocketException {
//创建服务器端DatagramSocket,指定端口
socket = new DatagramSocket(port);
}
@Override
public void run() {
while (true) {
byte[] buffer = new byte[MAX_UDP_DATA_SIZE];
packet = new DatagramPacket(buffer, buffer.length);
try {
log.info("waiting udp data!");
socket.receive(packet);
new Thread(new Process(packet)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Process implements Runnable {
public Process(DatagramPacket packet) throws UnsupportedEncodingException {
// 接收到的UDP信息,然后解码
byte[] buffer = packet.getData();
String data = new String(buffer, "UTF-8").trim();
log.info("UDP Received Data:{}", data);
}
@Override
public void run() {
try {
log.info("Start UDP Response.");
//1.定义客户端的地址、端口号、数据
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] data2 = "{'request':'alive','errcode':'0'}".getBytes();
//2.创建数据报,包含响应的数据信息
DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
//3.响应客户端
socket.send(packet2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("UDPListener destroyed!");
}
}
3.使用工具发送请求到本地9072端口。
4.获取数据封装入库
为什么写这一层,是因为在实际开发中可能需要注入某一个service来将数据入库,但新建线程中是无法直接使用autowired来注入service的,所以后续的操作是来解决这方面的问题的。如果没有此需要,可以直接跳过。
直接复制下面代码到项目。
package com.genew.nms.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author Salong
* @date 2022/5/26 14:35
* @Email:salong0503@aliyun.com
*/
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
}
public static Object getBeanByName(String beanName) {
if (applicationContext == null) {
return null;
}
return applicationContext.getBean(beanName);
}
public static <T> T getBean(Class<T> type) {
return applicationContext.getBean(type);
}
}
然后在类中取消使用autowired来注入sevice,使用下面的方式来获取service对象。
IBulkCallRecordService recordService = ApplicationContextUtil.getBean(IBulkCallRecordService.class);