cmt
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user