需求描述
客户端发送16进制的UDP报文,SprigBoot 通过 Socket 监听端口 接收报文,进行业务处理后返回客户端。
创建 Socket 监听类
注意 类上需声明 @WebListener
package com.lanlinker.netty.paycard.server;
import com.lanlinker.netty.paycard.entity.DoorSendMessage;
import com.lanlinker.netty.paycard.util.HexConvert;
import com.lanlinker.netty.paycard.util.IcCardUtil;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
* @author aaron
* @since 2021-01-28
*/
@Slf4j
@WebListener
public class UdpListener implements ServletContextListener {
private static int udpPort = 8801;
private static int maxUdpDataSize = 128;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
log.info("========>监听UDP数据包,监听端口 {} <======== ", udpPort);
try {
executeUdpMsg(udpPort);
} catch (SocketException e) {
log.error(e.getMessage());
}
}
private void executeUdpMsg(int port) throws SocketException {
//创建服务器端DatagramSocket,指定端口
DatagramSocket socket = new DatagramSocket(port);
log.info("=======创建数据报,用于接收客户端发送的数据======");
int a = 0;
while (true) {
byte[] buffer = new byte[maxUdpDataSize];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
log.info("=======端口 {} 等待接收消息 ======", udpPort);
socket.receive(packet);
// 接收到的UDP信息,然后解码
buffer = packet.getData();
InetAddress address = packet.getAddress();
String ip = address.getHostAddress();
int targetPort = packet.getPort();
log.info("=========接收到来自" + ip + ":" + targetPort + "的消息:" + HexConvert.BinaryToHexString(buffer));
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
log.info("========> 关闭监听UDP数据包,监听端口 {} <======== ", udpPort);
}
}
十六进制转换工具类
import java.util.LinkedList;
/**
* @author aaron
* @since 2021-01-27
*/
public class HexConvert {
public static String convertStringToHex(String str) {
char[] chars = str.toCharArray();
StringBuffer hex = new StringBuffer();
for (int i = 0; i < chars.length; i++) {
hex.append(Integer.toHexString((int) chars[i]));
}
return hex.toString();
}
public static String convertHexToString(String hex) {
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
for (int i = 0; i < hex.length() - 1; i += 2) {
String s = hex.substring(i, (i + 2));
int decimal = Integer.parseInt(s, 16);
sb.append((char) decimal);
sb2.append(decimal);
}
return sb.toString();
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
// toUpperCase将字符串中的所有字符转换为大写
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
// toCharArray将此字符串转换为一个新的字符数组。
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
//返回匹配字符
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
//将字节数组转换为short类型,即统计字符串长度
public static short bytes2Short2(byte[] b) {
short i = (short) (((b[1] & 0xff) << 8) | b[0] & 0xff);
return i;
}
//将字节数组转换为16进制字符串
public static String BinaryToHexString(byte[] bytes) {
String hexStr = "0123456789ABCDEF";
String result = "";
String hex = "";
for (byte b : bytes) {
hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4));
hex += String.valueOf(hexStr.charAt(b & 0x0F));
result += hex + " ";
}
return result;
}
//将字节数组转换为16进制字符串
public static LinkedList<String> binaryToLinkedListString(byte[] bytes) {
LinkedList<String> linkedList = new LinkedList<>();
String hexStr = "0123456789ABCDEF";
String result = "";
String hex = "";
for (byte b : bytes) {
hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4));
hex += String.valueOf(hexStr.charAt(b & 0x0F));
linkedList.add(hex);
}
return linkedList;
}
public static void main(String[] args) {
System.out.println("======ASCII码转换为16进制======");
String str = "*00007VERSION\\n1$";
System.out.println("字符串: " + str);
String hex = HexConvert.convertStringToHex(str);
System.out.println("====转换为16进制=====" + hex);
System.out.println("======16进制转换为ASCII======");
System.out.println("Hex : " + hex);
System.out.println("ASCII : " + HexConvert.convertHexToString(hex));
byte[] bytes = HexConvert.hexStringToBytes(hex);
System.out.println(HexConvert.BinaryToHexString(bytes));
}
创建客户端用于发送报文
@Slf4j
public class UdpClient {
public static void send(String ip, int port, byte[] content) {
try {
DatagramSocket socket = new DatagramSocket();
SocketAddress socketAddress = new InetSocketAddress(ip, port);
//参数1.数据 2.数据长度
DatagramPacket packet = new DatagramPacket(content, content.length, socketAddress);
String str = HexConvert.BinaryToHexString(content);
log.info("目标IP:" + ip + ",目标端口:" + port + ",发送的报文:" + str);
socket.send(packet);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
启动类上声明 @ServletComponentScan
@SpringBootApplication
@ServletComponentScan
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
配置文件 配置 server端口
server:
port: 8080
启动项目,测试类进行测试
public class Test {
public static void main(String[] args){
//16进制的 报文 数组
byte[] message = new byte[1024];
message[0] = (byte) 0x01;
message[1] = (byte) 0x02;
message[2] = (byte) 0x03;
message[3] = (byte) 0x04;
message[4] = (byte) 0x05;
message[8] = (byte) 0x0E;
UdpClient.send("127.0.0.1", 8801, message);
}
}
项目源码
Springboot项目模拟udp报文进行测试
相关文章【ServletContextListener中使用spring容器的bean】