一个java类实现UDP代理转发

概述

实现一个UDP代理服务器,它监听一个指定的端口,将接收到的UDP数据包转发到目标主机,并将目标主机的响应转发回原始客户端。使用线程池来异步处理响应,并使用日志记录器来记录不同级别的日志信息。

源代码

java 复制代码
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class UDPProxy {

    private final int listenPort;
    private final String targetHost;
    private final int targetPort;

    private final Map<DatagramSocket, DatagramPacket> downPacketCache = new ConcurrentHashMap<>();
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 16,
            60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(200), new ThreadPoolExecutor.CallerRunsPolicy());

    private static final Logger logger = Logger.getLogger("UDPProxy");


    public UDPProxy(int listenPort, String targetHost, int targetPort) {
        this.listenPort = listenPort;
        this.targetHost = targetHost;
        this.targetPort = targetPort;
        //设置日志级别
        logger.setLevel(Level.INFO);
    }

    public void start() {
        try (DatagramSocket thisSocket = new DatagramSocket(listenPort)) {
            byte[] receiveData = new byte[4096];
            logger.warning("UDP Proxy started, listening on port " + listenPort);
            Map<InetAddress, DatagramSocket> upSocketCache = new ConcurrentHashMap<>();
            while (true) {
                DatagramPacket upPacket = new DatagramPacket(receiveData, receiveData.length);
                thisSocket.receive(upPacket);
                byte[] data = upPacket.getData();
                int length = upPacket.getLength();
                InetAddress clientAddress = upPacket.getAddress();
                logger.warning("[UP] Size:" + length + ",from" + clientAddress + ":" + upPacket.getPort());
                logger.info("[UP] Packet:" + new String(data, 0, length, StandardCharsets.UTF_8));
                // Forward the packet to the target host
                InetAddress targetAddress = InetAddress.getByName(targetHost);
                DatagramPacket sendPacket = new DatagramPacket(data, length, targetAddress, targetPort);
                DatagramSocket upSocket = upSocketCache.get(clientAddress);
                if (upSocket == null) {
                    upSocket = new DatagramSocket();
                    upSocketCache.put(clientAddress, upSocket);
                    downPacketCache.put(upSocket, upPacket);
                    upSocket.send(sendPacket);
                    responseListener(thisSocket, upSocket);
                } else {
                    upSocket.send(sendPacket);
                }
            }
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Error in UDPProxy", e);
        }
    }

    private void responseListener(DatagramSocket thisSocket, DatagramSocket upSocket) {
        executor.execute(() -> {
            while (true) {
                byte[] downData = new byte[4096];
                DatagramPacket downPacket = new DatagramPacket(downData, downData.length);
                byte[] data = downPacket.getData();
                InetAddress downPacketAddress;
                try {
                    upSocket.receive(downPacket);
                    downPacketAddress = downPacket.getAddress();
                    int length = downPacket.getLength();
                    logger.warning("[DOWN] Size:" + length + ",From" + downPacketAddress + ":" + downPacket.getPort());
                    logger.info("[DOWN] Packet:"+ new String(data, 0, length, StandardCharsets.UTF_8));
                    DatagramPacket datagramPacket = downPacketCache.get(upSocket);
                    if (datagramPacket != null) {
                        datagramPacket.setData(data);
                        thisSocket.send(datagramPacket);
                    }
                } catch (IOException e) {
                    logger.log(Level.SEVERE, "Error in responseListener", e);
                }
            }
        });
    }

    public static void main(String[] args) {
        if (args.length != 3) {
            logger.warning("Usage: java UDPProxy <listenPort> <targetHost> <targetPort>");
            System.exit(1);
        }

        int listenPort = Integer.parseInt(args[0]);
        String targetHost = args[1];
        int targetPort = Integer.parseInt(args[2]);

        UDPProxy proxy = new UDPProxy(listenPort, targetHost, targetPort);
        proxy.start();
    }
}

代码启动

java UDPProxy <listenPort> <targetHost> <targetPort>

  • listenPort:代理服务器监听的端口。

  • targetHost:目标主机的地址。

  • targetPort:目标主机的端口。

bash 复制代码
 java UDPProxy 12681 192.168.18.76 6666

代码剖析

类和成员变量

  1. 成员变量

    • listenPort:代理服务器监听的端口。

    • targetHost:目标主机的地址。

    • targetPort:目标主机的端口。

    • downPacketCache:用于缓存下行数据包的映射。

    • executor:用于处理响应监听的线程池。

    • logger:用于日志记录的Logger对象。

构造方法

  • 构造方法

    • 初始化listenPorttargetHosttargetPort

    • 设置日志级别为INFO

start方法

  • start方法

    • 创建一个DatagramSocket实例,监听指定的端口。

    • 无限循环接收传入的UDP数据包。

    • 将接收到的数据包转发到目标主机。

    • 使用upSocketCache缓存每个客户端的DatagramSocket实例。

    • 调用responseListener方法监听目标主机的响应。

responseListener方法

  • responseListener方法

    • 使用线程池异步处理目标主机的响应。

    • 接收目标主机的响应数据包。

    • downPacketCache中获取原始客户端的数据包,并将响应数据包发送回原始客户端。

main方法

  • main方法

    • 解析命令行参数,创建UDPProxy实例并启动代理服务器。
相关推荐
Michael_lcf35 分钟前
Java的UDP通信:DatagramSocket和DatagramPacket
java·开发语言·udp
我也要当昏君2 小时前
6.3 文件传输协议 (答案见原书 P277)
网络
Greedy Alg2 小时前
Socket编程学习记录
网络·websocket·学习
刘逸潇20053 小时前
FastAPI(二)——请求与响应
网络·python·fastapi
软件技术员3 小时前
使用ACME自动签发SSL 证书
服务器·网络协议·ssl
我也要当昏君3 小时前
6.4 电子邮件 (答案见原书 P284)
网络协议
Mongnewer3 小时前
通过虚拟串口和网络UDP进行数据收发的Delphi7, Lazarus, VB6和VisualFreeBasic实践
网络
我也要当昏君4 小时前
6.5 万维网(答案见原书P294)
网络
嶔某4 小时前
网络:传输层协议UDP和TCP
网络·tcp/ip·udp
文火冰糖的硅基工坊4 小时前
[嵌入式系统-154]:各种工业现场总线比较
网络·自动驾驶·硬件架构