Springboot持续监听端口 并通过udp协议收发报文

该博客介绍了如何使用SpringBoot创建一个UDP监听服务,接收客户端发送的16进制报文,并进行业务处理。通过`@WebListener`注解的`UdpListener`类监听端口,接收到数据后进行十六进制转换。同时,提供了一个`UdpClient`类用于发送16进制报文到指定IP和端口。整个流程包括了Socket通信、十六进制转换工具类的实现以及SpringBoot应用的配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求描述

客户端发送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】

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值