一个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实例并启动代理服务器。
相关推荐
hellojackjiang201143 分钟前
开源轻量级IM框架MobileIMSDK的鸿蒙NEXT客户端库已发布
网络·即时通讯·im开发·mobileimsdk-鸿蒙端
WebDeveloper20011 小时前
如何使用美国域名中心US Domain Center和WordPress创建商业网站
运维·服务器·css·网络·html
车载诊断技术3 小时前
电子电气架构 --- 什么是EPS?
网络·人工智能·安全·架构·汽车·需求分析
KevinRay_3 小时前
Python超能力:高级技巧让你的代码飞起来
网络·人工智能·python·lambda表达式·列表推导式·python高级技巧
2301_819287124 小时前
ce第六次作业
linux·运维·服务器·网络
CIb0la4 小时前
GitLab 停止为中国区用户提供 GitLab.com 账号服务
运维·网络·程序人生
Black_mario4 小时前
链原生 Web3 AI 网络 Chainbase 推出 AVS 主网, 拓展 EigenLayer AVS 应用场景
网络·人工智能·web3
Aileen_0v04 小时前
【AI驱动的数据结构:包装类的艺术与科学】
linux·数据结构·人工智能·笔记·网络协议·tcp/ip·whisper
中科岩创5 小时前
中科岩创边坡自动化监测解决方案
大数据·网络·物联网
花鱼白羊5 小时前
TCP Vegas拥塞控制算法——baseRtt 和 minRtt的区别
服务器·网络协议·tcp/ip