This commit is contained in:
2026-09-29 10:49:51 +08:00
parent 6d6a199728
commit 100fad7d18
3 changed files with 280 additions and 2 deletions
@@ -0,0 +1,277 @@
package org.kne.cloud.network;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.MembershipKey;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.spi.SelectorProvider;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 自制的 UDP AIO 通道,内部使用线程池模拟异步收包。
* 用户只需设置回调,无需自己管理线程。
*
* 完整委托了 DatagramChannel 的所有公共方法。
*/
public class AsynchronousDatagramChannel implements AutoCloseable {
private final DatagramChannel delegate;
private final ExecutorService workerPool;
private final AtomicBoolean running = new AtomicBoolean(true);
private volatile ReceiveHandler handler;
private final int bufferSize;
private int threadCount;
// ==================== 回调接口 ====================
@FunctionalInterface
public interface ReceiveHandler {
void onReceive(SocketAddress from, ByteBuffer data);
}
// ==================== 构造方法 ====================
public AsynchronousDatagramChannel() throws IOException {
this(65535, Runtime.getRuntime().availableProcessors());
}
public AsynchronousDatagramChannel(int bufferSize, int threadCount) throws IOException {
this.bufferSize = bufferSize;
this.delegate = DatagramChannel.open();
delegate.configureBlocking(true);
this.threadCount=threadCount;
this.workerPool = Executors.newFixedThreadPool(threadCount, r -> {
Thread t = new Thread(r, "AsyncDatagramReader");
t.setDaemon(true);
return t;
});
}
public void startWorkers() {
for (int i = 0; i < threadCount; i++) {
workerPool.submit(this::readerLoop);
}
}
// ==================== 核心方法 ====================
public void setReceiveHandler(ReceiveHandler handler) {
this.handler = handler;
}
private void readerLoop() {
ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize);
while (running.get()) {
try {
buffer.clear();
SocketAddress from = delegate.receive(buffer);
if (from == null) {
continue;
}
buffer.flip();
ReceiveHandler localHandler = handler;
if (localHandler != null) {
localHandler.onReceive(from, buffer);
}
} catch (IOException e) {
if (running.get()) {
e.printStackTrace();
}
break;
}
}
}
public int send(ByteBuffer data, SocketAddress target) throws IOException {
return delegate.send(data, target);
}
// ==================== DatagramChannel 委托方法 ====================
// --- 连接相关 ---
public DatagramChannel connect(SocketAddress remote) throws IOException {
return delegate.connect(remote);
}
public DatagramChannel disconnect() throws IOException {
return delegate.disconnect();
}
public boolean isConnected() {
return delegate.isConnected();
}
// --- 绑定相关 ---
public DatagramChannel bind(SocketAddress local) throws IOException {
return delegate.bind(local);
}
public SocketAddress getLocalAddress() throws IOException {
return delegate.getLocalAddress();
}
public SocketAddress getRemoteAddress() throws IOException {
return delegate.getRemoteAddress();
}
// --- 读写相关 ---
public int read(ByteBuffer dst) throws IOException {
return delegate.read(dst);
}
public long read(ByteBuffer[] dsts) throws IOException {
return delegate.read(dsts);
}
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
return delegate.read(dsts, offset, length);
}
public int write(ByteBuffer src) throws IOException {
return delegate.write(src);
}
public long write(ByteBuffer[] srcs) throws IOException {
return delegate.write(srcs);
}
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
return delegate.write(srcs, offset, length);
}
// --- 接收相关 ---
public SocketAddress receive(ByteBuffer dst) throws IOException {
return delegate.receive(dst);
}
// --- 多播 (Multicast) ---
public MembershipKey join(InetAddress group, NetworkInterface interf) throws IOException {
return delegate.join(group, interf);
}
public MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source) throws IOException {
return delegate.join(group, interf, source);
}
// --- 选项相关 ---
public <T> DatagramChannel setOption(SocketOption<T> name, T value) throws IOException {
return delegate.setOption(name, value);
}
public <T> T getOption(SocketOption<T> name) throws IOException {
return delegate.getOption(name);
}
public Set<SocketOption<?>> supportedOptions() {
return delegate.supportedOptions();
}
// --- 阻塞模式 ---
public boolean isBlocking() {
return delegate.isBlocking();
}
// --- 选择器相关 ---
public SelectableChannel configureBlocking(boolean block) throws IOException {
return delegate.configureBlocking(block);
}
public SelectorProvider provider() {
return delegate.provider();
}
public int validOps() {
return delegate.validOps();
}
public SelectionKey keyFor(Selector sel) {
return delegate.keyFor(sel);
}
public SelectionKey register(Selector sel, int ops) throws ClosedChannelException {
return delegate.register(sel, ops);
}
public SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException {
return delegate.register(sel, ops, att);
}
// --- 状态查询 ---
public boolean isOpen() {
return delegate.isOpen() && running.get();
}
public DatagramSocket socket() {
return delegate.socket();
}
// ==================== 关闭方法 ====================
@Override
public void close() throws Exception {
running.set(false);
workerPool.shutdownNow();
delegate.close();
}
// ==================== 静态工厂方法 ====================
public static AsynchronousDatagramChannel open() throws IOException {
return new AsynchronousDatagramChannel();
}
public static AsynchronousDatagramChannel open(int bufferSize) throws IOException {
return new AsynchronousDatagramChannel(bufferSize, Runtime.getRuntime().availableProcessors());
}
public static AsynchronousDatagramChannel open(int bufferSize, int threadCount) throws IOException {
return new AsynchronousDatagramChannel(bufferSize, threadCount);
}
// ==================== 测试示例 ====================
public static void main(String[] args) throws Exception {
int port = 4567;
AsynchronousDatagramChannel channel = AsynchronousDatagramChannel.open();
channel.bind(new InetSocketAddress(port));
channel.setReceiveHandler((from, data) -> {
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
String msg = new String(bytes);
System.out.println("Received from " + from + ": " + msg);
});
System.out.println("Echo server running on port " + port);
System.out.println("Press Enter to stop...");
System.in.read();
channel.close();
System.out.println("Server stopped.");
}
}
@@ -686,7 +686,7 @@ public class KLALBController {
context.syncToSystem();
// System.out.println(context);
try {
NTPv4Protocol nvc = new NTPv4Protocol(context,
/*NTPv4Protocol nvc = new NTPv4Protocol(context,
new MultiProtocolSocketAddress(iproxyname + "datagram","0.0.0.0",123));
srv6Router.addSRv6RouterListener(new SRv6RouterListener() {
@@ -718,7 +718,7 @@ public class KLALBController {
return true;
});
}
});
});*/
nvc2 = new NTPv4Protocol(context, new MultiProtocolSocketAddress("udp","0.0.0.0",0));
System.out.println(" Loaded: NTP Module");