Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23731a4851 | ||
|
|
47c28d1d70 | ||
|
|
1cc34ea00a | ||
|
|
4f2fb8b8fb | ||
|
|
189b14a743 | ||
|
|
3b73e2b613 | ||
|
|
ec51e5a778 | ||
|
|
c0e73bce55 | ||
|
|
b898e4c5be | ||
|
|
61bc066f82 | ||
|
|
7f46c1b8c9 | ||
|
|
156d74bbe3 | ||
|
|
862b860020 | ||
|
|
100fad7d18 | ||
|
|
6d6a199728 | ||
|
|
21b975676d | ||
|
|
2c111770b3 |
@@ -2,34 +2,17 @@
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="lib" path="lib/gson-2.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/javassist.jar" sourcepath="C:/Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1686963856070/source/javassist-3.29.2-GA-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/ini4j.jar"/>
|
||||
<classpathentry kind="lib" path="lib/toml4j-0.7.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/pcap4j-core-1.8.2.jar" sourcepath="C:/Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1725520274095/source/pcap4j-core-1.8.2-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/pcap4j-packetfactory-static-1.8.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/pcap4j-sample-1.8.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9.jar"/>
|
||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-javadoc.jar"/>
|
||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-tests.jar"/>
|
||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0.jar" sourcepath="lib/disruptor-4.0.0-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0-javadoc.jar"/>
|
||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/KNElib1.0.jar"/>
|
||||
<classpathentry kind="lib" path="lib/KNEOptimize.jar"/>
|
||||
<classpathentry kind="lib" path="lib/JavaTUN0.3.jar"/>
|
||||
<classpathentry kind="lib" path="lib/uuid-creator-6.1.1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6-javadoc.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/KNEOptimize.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25">
|
||||
<attributes>
|
||||
<attribute name="module" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="lib/jfreechart-1.5.3.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jfreechart-1.5.3-javadoc.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jfreechart-1.5.3-sources.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="jctools-core-jdk11-4.0.7">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jctools-core-jdk11-4.0.7.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jctools-core-jdk11-4.0.7-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
@@ -2,5 +2,6 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/dashboard" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -250,5 +250,6 @@
|
||||
</orderEntry>
|
||||
<orderEntry type="jdk" jdkName="jdk-26.0.1" jdkType="JavaSDK" />
|
||||
<orderEntry type="library" name="jfreechart-1.5.3" level="project" />
|
||||
<orderEntry type="library" name="jctools-core-jdk11-4.0.7" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 318 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 141 KiB |
@@ -117,3 +117,11 @@ enablewebapi=Enable Web API
|
||||
weblistenaddr=Web API listen address
|
||||
invaildweblistenaddr=Invalid Web API listen address
|
||||
enabletun=Enable TUN adapter
|
||||
congestionmonitor=Congestion control monitor
|
||||
rttbaseline=RTT baseline
|
||||
rtt=RTT
|
||||
rttmax=RTT max
|
||||
rttmin=RTT min
|
||||
rto=RTO
|
||||
cpuload=CPU load
|
||||
ramusage=RAM usage
|
||||
@@ -117,3 +117,11 @@ enablewebapi=启用 Web API
|
||||
weblistenaddr=Web API 监听地址:端口
|
||||
invaildweblistenaddr=无效的 Web API 监听地址:端口
|
||||
enabletun=启用TUN虚拟网卡
|
||||
congestionmonitor=拥塞控制监视器
|
||||
rttbaseline=往返延迟基线
|
||||
rtt=往返延迟
|
||||
rttmax=往返延迟上限
|
||||
rttmin=往返延迟下限
|
||||
rto=重传超时
|
||||
cpuload=CPU负载
|
||||
ramusage=RAM占用率
|
||||
@@ -5,6 +5,9 @@ import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.kne.math.Long128;
|
||||
|
||||
@@ -256,4 +259,27 @@ public class NTPTimestamps {
|
||||
.setBit(63);
|
||||
}
|
||||
}
|
||||
|
||||
public static Long128 median(List<Long128> values) {
|
||||
Objects.requireNonNull(values);
|
||||
if ( values.isEmpty()) {
|
||||
throw new IllegalArgumentException("列表不能为空");
|
||||
}
|
||||
|
||||
// 1. 创建副本并排序
|
||||
List<Long128> sorted = new ArrayList<>(values);
|
||||
sorted.sort(Long128::compareTo);
|
||||
|
||||
// 2. 计算中位数
|
||||
int size = sorted.size();
|
||||
if (size % 2 == 1) {
|
||||
// 奇数个:取中间值
|
||||
return sorted.get(size / 2);
|
||||
} else {
|
||||
// 偶数个:取中间两个的平均值
|
||||
Long128 left = sorted.get(size / 2 - 1);
|
||||
Long128 right = sorted.get(size / 2);
|
||||
return left.add(right).divide(Long128.valueOf(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -148,21 +150,39 @@ public class IPMulticastDiscovery implements Closeable, AutoCloseable {
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
// 1. 接收用的 ThreadLocal 缓冲区
|
||||
private static final ThreadLocal<ByteBuffer> RX_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(2048));
|
||||
// 2. 发送用的 ThreadLocal 缓冲区 (广播包一般很小)
|
||||
private static final ThreadLocal<ByteBuffer> TX_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(2048));
|
||||
|
||||
private MultiProtocolSocketAddress receive() throws IOException {
|
||||
byte[] b = new byte[65535];
|
||||
DatagramPacket dp = new DatagramPacket(b, b.length);
|
||||
ByteBuffer bbf = RX_BUFFER.get();
|
||||
bbf.clear(); // 重置 position=0, limit=2048
|
||||
|
||||
// 借用底层数组
|
||||
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||
soc.receive(dp);
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(b, 0, dp.getLength());
|
||||
DataInputStream dis = new DataInputStream(bis);
|
||||
String val = dis.readUTF();
|
||||
long h=dis.readLong();
|
||||
long l=dis.readLong();
|
||||
UUID uid=new UUID(h, l);
|
||||
dis.close();
|
||||
|
||||
// 限制可读范围
|
||||
int length = dp.getLength();
|
||||
bbf.limit(length);
|
||||
|
||||
// 直接读 UTF 字符串 (不用 DataInputStream)
|
||||
// 读取前两个字节的长度,然后创建 String
|
||||
int strLen = bbf.getShort() & 0xFFFF; // 无符号转 int
|
||||
byte[] strBytes = new byte[strLen]; // 这里为了 String 还是得分配一次,但很小
|
||||
bbf.get(strBytes);
|
||||
String val = new String(strBytes, StandardCharsets.UTF_8);
|
||||
|
||||
// 直接读两个 Long 拼成 UUID
|
||||
long h = bbf.getLong();
|
||||
long l = bbf.getLong();
|
||||
UUID uid = new UUID(h, l); // UUID 对象很小,年轻代瞬间回收,不用池化
|
||||
|
||||
MultiProtocolSocketAddress mpsa = new MultiProtocolSocketAddress(val);
|
||||
if(mpsa.getInetAddress().isAnyLocalAddress()){
|
||||
mpsa=new MultiProtocolSocketAddress(mpsa.getProtocol(),dp.getAddress().getHostAddress(),mpsa.getPort());
|
||||
|
||||
if (mpsa.getInetAddress().isAnyLocalAddress()) {
|
||||
mpsa = new MultiProtocolSocketAddress(mpsa.getProtocol(), dp.getAddress().getHostAddress(), mpsa.getPort());
|
||||
}
|
||||
if(debug) {
|
||||
if(uid.equals(selfUUID)) {
|
||||
@@ -176,15 +196,23 @@ public class IPMulticastDiscovery implements Closeable, AutoCloseable {
|
||||
}
|
||||
|
||||
private void send(MultiProtocolSocketAddress multiProtocolSocketAddress) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream dops = new DataOutputStream(baos);
|
||||
dops.writeUTF(multiProtocolSocketAddress.toString());
|
||||
dops.writeLong(selfUUID.getMostSignificantBits());
|
||||
dops.writeLong(selfUUID.getLeastSignificantBits());
|
||||
dops.close();
|
||||
byte[] b = baos.toByteArray();
|
||||
DatagramPacket dp = new DatagramPacket(b, b.length, group);
|
||||
ByteBuffer bbf = TX_BUFFER.get();
|
||||
bbf.clear(); // 重置
|
||||
|
||||
// 写字符串 (长度 + 字节)
|
||||
byte[] strBytes = multiProtocolSocketAddress.toString().getBytes(StandardCharsets.UTF_8);
|
||||
bbf.putShort((short) strBytes.length);
|
||||
bbf.put(strBytes);
|
||||
|
||||
// 写 UUID
|
||||
bbf.putLong(selfUUID.getMostSignificantBits());
|
||||
bbf.putLong(selfUUID.getLeastSignificantBits());
|
||||
|
||||
bbf.flip(); // 准备读取
|
||||
|
||||
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit(), group);
|
||||
soc.send(dp);
|
||||
|
||||
if(debug)
|
||||
System.out.println(ninterface.getDisplayName()+" 发送广播:"+ multiProtocolSocketAddress +" "+group+" "+selfUUID);
|
||||
|
||||
|
||||
@@ -11,14 +11,13 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
|
||||
private long MIN_RTTVAR = 5000000L;
|
||||
private volatile long RTTMin = 1000000000L;
|
||||
private volatile long RTTVar = 1000000000L;
|
||||
private volatile long RTTAvg = 1000000000L;
|
||||
private volatile long RTTAvg2 = 1000000000L;
|
||||
private volatile long RTTTotal = 0;
|
||||
private volatile long RTTCount = 0;
|
||||
private volatile long RTO = 1000000000L;
|
||||
|
||||
|
||||
private RTTEstimator rttEstimator=new RTTEstimator();
|
||||
|
||||
|
||||
private volatile long window=MIN_WINDOW;
|
||||
@@ -54,10 +53,7 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
||||
} else {
|
||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||
}
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||
rttEstimator.putRTT(latencyns);
|
||||
|
||||
RTTTotal += latencyns;
|
||||
RTTCount++;
|
||||
@@ -93,13 +89,13 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
public void putLoss(long packetSize, long lossns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
return rttEstimator.getRTO();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,4 +132,29 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
||||
return "BBR";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBaseRTT() {
|
||||
return rttEstimator.getBaseRTT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentRTT() {
|
||||
return rttEstimator.getCurrentRTT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getUpperDelayBound() {
|
||||
return MAX_GAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLowerDelayBound() {
|
||||
return MIN_GAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBurstLimit() {
|
||||
return burstLimit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ public interface CongestionAlgorithm {
|
||||
public void reset();
|
||||
public void setWindowControlConsumer(Consumer<Long>windowControlConsumer);
|
||||
public void putAck(long packetSize,long RTTns,boolean ecn);
|
||||
default public void putAck(long packetSize,long RTTns,long OWDup,boolean ecn) {
|
||||
putAck(packetSize,RTTns,ecn);
|
||||
}
|
||||
public void putLoss(long packetSize,long lossns,int losscounter);
|
||||
public void putLoss(long packetSize,long lossns);
|
||||
public void setCurrentWindowUsed(long maxwindow);
|
||||
public void setCurrentBandwidth(long bandwidth);
|
||||
public long getRTO();
|
||||
public String getName();
|
||||
|
||||
public long getBaseRTT();
|
||||
|
||||
public long getCurrentRTT();
|
||||
}
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
package org.kne.cloud.network.congestion;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jctools.counters.FixedSizeStripedLongCounter;
|
||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||
|
||||
public class DCTCP2CongestionAlgorithm implements CongestionAlgorithm {
|
||||
|
||||
private static final long BURST_TIME = 1000000L;
|
||||
private static final long BIAS = 2000000L;
|
||||
private static long MIN_WINDOW = 8192;
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
|
||||
private long MIN_RTTVAR = 100000000L;
|
||||
private volatile long RTTVar = 1000000000L;
|
||||
private volatile long RTTAvg = 1000000000L;
|
||||
private double ECNAvg2 = 0L;
|
||||
private double alpha=0;
|
||||
private volatile FixedSizeStripedLongCounter ECNSize = KLALBUtils.createCounter();
|
||||
private volatile FixedSizeStripedLongCounter TotalSize = KLALBUtils.createCounter();
|
||||
private volatile long RTO = 500000000L;
|
||||
|
||||
|
||||
private volatile long window=MIN_WINDOW;
|
||||
private volatile long maxwindow = 99999999999L;
|
||||
private volatile long congressWindowSize=MIN_WINDOW;
|
||||
|
||||
private long RTTstartTime = System.nanoTime();
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
window = MIN_WINDOW;
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||
this.windowControlConsumer = windowControlConsumer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||
|
||||
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||
|
||||
if(ecn) {
|
||||
ECNSize.inc(packetSize);
|
||||
}
|
||||
TotalSize.inc(packetSize);
|
||||
|
||||
|
||||
long curr=System.nanoTime();
|
||||
if(curr-RTTstartTime>(RTTAvg+BIAS)) {
|
||||
RTTstartTime=curr;
|
||||
|
||||
long totalSize=TotalSize.getAndReset();
|
||||
long ecnSize=ECNSize.getAndReset();
|
||||
if(totalSize!=0) {
|
||||
ECNAvg2=ecnSize/(double)totalSize;
|
||||
alpha=(alpha*7+ECNAvg2)/8;
|
||||
}
|
||||
|
||||
if(ECNAvg2>0.5) {
|
||||
congressWindowSize-=200;
|
||||
}else if(ECNAvg2>0.01){
|
||||
congressWindowSize+=200;
|
||||
}else {
|
||||
congressWindowSize+=4000;
|
||||
}
|
||||
//System.out.println(ECNAvg2);
|
||||
//System.out.println(speed+" "+window);
|
||||
|
||||
updateWindowSize();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void updateWindowSize() {
|
||||
if(congressWindowSize<MIN_WINDOW) {
|
||||
congressWindowSize=MIN_WINDOW;
|
||||
}else if(congressWindowSize>maxwindow) {
|
||||
congressWindowSize=maxwindow;
|
||||
}
|
||||
window=Math.max( congressWindowSize,MIN_WINDOW);
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentWindowUsed(long used) {
|
||||
this.maxwindow=(long) (used*1.5)+MIN_WINDOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentBandwidth(long bandwidth) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DCTCP2";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,16 +13,13 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
|
||||
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||
private long MIN_RTTVAR = 100000000L;
|
||||
private volatile long RTTMin = 1000000000L;
|
||||
private volatile long RTTVar = 1000000000L;
|
||||
private volatile long RTTAvg = 1000000000L;
|
||||
private double ECNAvg2 = 0L;
|
||||
private double alpha=0;
|
||||
private volatile AtomicLong ECNSize = new AtomicLong(0);
|
||||
private volatile AtomicLong TotalSize = new AtomicLong(0);
|
||||
private volatile long RTO = 1000000000L;
|
||||
|
||||
private RTTEstimator rttEstimator=new RTTEstimator(100000000L);
|
||||
|
||||
|
||||
private volatile long window=MIN_WINDOW;
|
||||
@@ -54,14 +51,7 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
||||
} else {
|
||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||
}
|
||||
if (firstUpdate.compareAndSet(true, false)) {
|
||||
RTTAvg = latencyns;
|
||||
RTTVar = latencyns / 2;
|
||||
} else {
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||
}
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||
rttEstimator.putRTT(latencyns);
|
||||
|
||||
if(ecn) {
|
||||
ECNSize.addAndGet(packetSize);
|
||||
@@ -88,7 +78,7 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
||||
}
|
||||
}else {
|
||||
if(windowUsed*3L>=congressWindowSize) {
|
||||
congressWindowSize+=4000;
|
||||
congressWindowSize+=4096;
|
||||
updateWindowSize();
|
||||
}
|
||||
}
|
||||
@@ -109,13 +99,13 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
public void putLoss(long packetSize, long lossns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
return rttEstimator.getRTO();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,6 +123,15 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
||||
return "DCTCP";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBaseRTT() {
|
||||
return rttEstimator.getBaseRTT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentRTT() {
|
||||
return rttEstimator.getCurrentRTT();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,4 +4,7 @@ public interface DetnetCongestionAlgorithm extends CongestionAlgorithm {
|
||||
public void setUpperDelayBound(double upper);
|
||||
public void setLowerDelayBound(double lower);
|
||||
public void setBurstLimit(double limit);
|
||||
public double getUpperDelayBound( );
|
||||
public double getLowerDelayBound();
|
||||
public double getBurstLimit();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.kne.cloud.network.congestion;
|
||||
|
||||
import org.jctools.queues.MpscArrayQueue;
|
||||
import org.jctools.queues.MessagePassingQueue;
|
||||
import org.jctools.queues.varhandle.MpscVarHandleArrayQueue;
|
||||
import org.kne.cloud.network.ThreadTool;
|
||||
import org.kne.opencl64.Releaser;
|
||||
|
||||
@@ -82,7 +83,7 @@ class MpscMessageBatcherReleaser<T> extends Releaser<MpscMessageBatcher0<T>> {
|
||||
|
||||
class MpscMessageBatcher0<T> implements Runnable, MessageBatcher<T> {
|
||||
|
||||
private final MpscArrayQueue<T> queue;
|
||||
private final MessagePassingQueue<T> queue;
|
||||
private final int batchSize;
|
||||
private final long maxDelay;
|
||||
private volatile Consumer<List<T>> consumer;
|
||||
@@ -94,7 +95,7 @@ class MpscMessageBatcher0<T> implements Runnable, MessageBatcher<T> {
|
||||
public MpscMessageBatcher0(int batchSize, long maxDelay, int queueCapacity) {
|
||||
this.batchSize = batchSize;
|
||||
this.maxDelay = maxDelay;
|
||||
this.queue = new MpscArrayQueue<>(queueCapacity);
|
||||
this.queue = new MpscVarHandleArrayQueue<>(queueCapacity);
|
||||
|
||||
this.batchThread = ThreadTool.makeVDaemonThread("MpscMessageBatcher", this);
|
||||
this.batchThread.start();
|
||||
|
||||
@@ -31,7 +31,7 @@ public class NOCongestionAlgorithm implements CongestionAlgorithm{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
public void putLoss(long packetSize, long lossns) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
@@ -63,4 +63,14 @@ public class NOCongestionAlgorithm implements CongestionAlgorithm{
|
||||
return "NO";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBaseRTT() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentRTT() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package org.kne.cloud.network.congestion;
|
||||
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||
import org.kne.cloud.network.monitor.ArrayListTimestampMonitor;
|
||||
import org.kne.cloud.network.monitor.DelaySampler;
|
||||
import org.kne.cloud.network.monitor.TimestampMonitor;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* 线程安全的 RTT 平滑与 RTO 计算工具。
|
||||
* 基于 RFC 6298 的 Jacobson/Karels 算法。
|
||||
*
|
||||
* 公式:
|
||||
* RTTAvg = (RTTAvg * 7 + RTTns) / 8
|
||||
* RTTVar = (RTTVar * 3 + |RTTAvg - RTTns|) / 4
|
||||
* RTO = RTTAvg + max(MIN_RTTVAR, RTTVar * 4)
|
||||
*/
|
||||
public class RTTEstimator {
|
||||
|
||||
/** RTTVar 下限(纳秒),防止 RTO 过小。默认 20ms。 */
|
||||
private static final long DEFAULT_MIN_RTTVAR_NS = 20_000_000L;
|
||||
|
||||
private final AtomicLong curr;
|
||||
private final AtomicLong rttAvg;
|
||||
private final AtomicLong rttVar;
|
||||
private final AtomicLong rto;
|
||||
private final AtomicLong basertt;
|
||||
private final AtomicBoolean firstUpdate = new AtomicBoolean(true); // 首次标记
|
||||
private final long minRttVarNs;
|
||||
|
||||
|
||||
private long timewindowmax=500000000L;
|
||||
|
||||
long stime=System.nanoTime();
|
||||
|
||||
public RTTEstimator() {
|
||||
this(DEFAULT_MIN_RTTVAR_NS);
|
||||
}
|
||||
|
||||
public RTTEstimator(long minRttVarNs) {
|
||||
this.rttAvg = new AtomicLong(1000000000L);
|
||||
this.rttVar = new AtomicLong(1000000000L);
|
||||
this.curr = new AtomicLong(1000000000L);
|
||||
this.rto = new AtomicLong(1000000000L);
|
||||
this.basertt = new AtomicLong(1000000000L);
|
||||
this.minRttVarNs = minRttVarNs;
|
||||
}
|
||||
private final static long TIME_WINDOW=30000000000L;
|
||||
private final TimestampMonitor<UUID> rttMonitor=new ArrayListTimestampMonitor<UUID>(new HighAccuracyClock(),"RTTMonitor", 100, TIME_WINDOW);
|
||||
private final DelaySampler dsp=new DelaySampler();
|
||||
|
||||
public void update() {
|
||||
dsp.update();
|
||||
|
||||
if(dsp.getSnapshotPacketCount()>0&&dsp.getSnapshotTotalDelay()>0) {
|
||||
rttMonitor. recordPacket(KLALBUtils.createGlobalUUID(),0, 0, dsp.getAvgDelayNanos(),dsp.getMinDelayNanos());
|
||||
}
|
||||
|
||||
long time=System.nanoTime();
|
||||
if(time-stime>timewindowmax) {
|
||||
basertt.lazySet( rttMonitor.calculateMinDelay(TIME_WINDOW));
|
||||
stime=time;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 更新 RTT 估算值(线程安全)。
|
||||
*
|
||||
* @param rttNs 本次 RTT 测量值(纳秒)
|
||||
*/
|
||||
/**
|
||||
* 更新 RTT 估算值(线程安全,无锁)。
|
||||
*/
|
||||
public void putRTT(long rttNs) {
|
||||
if (rttNs < 0) {
|
||||
throw new IllegalArgumentException("RTT 不能为负数: " + rttNs);
|
||||
}
|
||||
dsp.recordDelay(rttNs);
|
||||
curr.lazySet(rttNs);
|
||||
// 首次更新:CAS 成功则直接初始化,无锁
|
||||
if (firstUpdate.compareAndSet(true, false)) {
|
||||
rttAvg.set(rttNs);
|
||||
rttVar.set(rttNs / 2);
|
||||
return;
|
||||
}
|
||||
|
||||
// 后续更新:CAS 循环保证原子性
|
||||
|
||||
long oldAvg = rttAvg.get();
|
||||
long newAvg = (oldAvg * 7 + rttNs) / 8;
|
||||
|
||||
long delta = Math.abs(oldAvg - rttNs);
|
||||
rttAvg.lazySet(newAvg);
|
||||
long oldVar = rttVar.get();
|
||||
long newVar = (oldVar * 3 + delta) / 4;
|
||||
rttVar.lazySet(newVar);
|
||||
|
||||
rto .lazySet( newAvg + Math.max(minRttVarNs, newVar * 4));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取平滑 RTT 平均值(纳秒)。
|
||||
*/
|
||||
public long getRTTAvg() {
|
||||
return rttAvg.getPlain();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 RTT 偏差(纳秒)。
|
||||
*/
|
||||
public long getRTTVar() {
|
||||
return rttVar.getPlain();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 RTO(重传超时时间,纳秒)。
|
||||
* RTO = RTTAvg + max(MIN_RTTVAR, RTTVar * 4)
|
||||
*/
|
||||
public long getRTO() {
|
||||
return rto.getPlain();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置估算器(用于连接重建等场景)。
|
||||
*/
|
||||
public void reset() {
|
||||
rttAvg.set(0);
|
||||
rttVar.set(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("RttEstimator{avg=%.3fms, var=%.3fms, rto=%.3fms}",
|
||||
rttAvg.get() / 1_000_000.0,
|
||||
rttVar.get() / 1_000_000.0,
|
||||
getRTO() / 1_000_000.0);
|
||||
}
|
||||
|
||||
public long getCurrentRTT() {
|
||||
return curr.get();
|
||||
}
|
||||
|
||||
public long getBaseRTT() {
|
||||
return basertt.get();
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,10 @@ import java.net.SocketException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
@@ -13,13 +16,15 @@ import java.util.function.Consumer;
|
||||
|
||||
import org.kne.cloud.network.NetworkPacket;
|
||||
import org.kne.cloud.network.ThreadTool;
|
||||
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||
import org.kne.cloud.network.klalb.SendItem;
|
||||
import org.kne.concurrent.ThreadParker;
|
||||
|
||||
public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Closeable, AutoCloseable {
|
||||
private final ScheduledFuture<?> checkerTask;
|
||||
private ThreadParker tp=new ThreadParker();
|
||||
|
||||
private Map<K, SendItem<V>> sendMap = new ConcurrentHashMap<>(2048);
|
||||
private volatile Map<K, SendItem<V>> sendMap = new ConcurrentHashMap<>(2048);
|
||||
private AtomicLong sendWindowUsed=new AtomicLong(0);
|
||||
//private LongAdder sendWindowUsed = new LongAdder();
|
||||
|
||||
@@ -56,8 +61,7 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
||||
this.removeAtResend = removeAtResend;
|
||||
this.algorithm = algorithm;
|
||||
this.windowSize=windowSize;
|
||||
Thread t = ThreadTool.makeVThread("重路由计时器线程", checker);
|
||||
t.start();
|
||||
this.checkerTask=KLALBScheduler.getScheduler().scheduleWithFixedDelay(checker,1,1, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public long getWindowSize() {
|
||||
@@ -131,16 +135,15 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
||||
algorithm.setCurrentWindowUsed(newWindow);
|
||||
}
|
||||
public V ack(K sequence) {
|
||||
return ack(sequence,false);
|
||||
return ack(sequence,0,false);
|
||||
}
|
||||
|
||||
public V ack(K sequence,boolean ecn) {
|
||||
public V ack(K sequence,long RTTns,boolean ecn) {
|
||||
SendItem<V> ipv6;
|
||||
if ((ipv6 = sendMap.remove(sequence)) != null) {
|
||||
long newWindow =sendWindowUsed.addAndGet(-ipv6.getPacketLength() );
|
||||
algorithm.setCurrentWindowUsed(newWindow);
|
||||
long RTTC = System.nanoTime() - ipv6.getSendtime();
|
||||
algorithm.putAck(ipv6.getPacketLength(), RTTC, ecn);
|
||||
algorithm.putAck(ipv6.getPacketLength(), RTTns, ecn);
|
||||
tp.unpark();
|
||||
// System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
||||
Lock lockx = lock;
|
||||
@@ -162,65 +165,15 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
||||
}
|
||||
}
|
||||
|
||||
public V ack(K sequence,boolean ecn,long OWDdown) {
|
||||
SendItem<V> ipv6;
|
||||
if ((ipv6 = sendMap.remove(sequence)) != null) {
|
||||
long newWindow =sendWindowUsed.addAndGet(-ipv6.getPacketLength() );
|
||||
algorithm.setCurrentWindowUsed(newWindow);
|
||||
long RTTC = System.nanoTime() - ipv6.getSendtime();
|
||||
algorithm.putAck(ipv6.getPacketLength(), RTTC,OWDdown, ecn);
|
||||
tp.unpark();
|
||||
// System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
||||
Lock lockx = lock;
|
||||
if (lockx != null) {
|
||||
lockx.lock();
|
||||
try {
|
||||
Condition cds = condition;
|
||||
if (cds != null) {
|
||||
cds.signalAll();
|
||||
}
|
||||
} finally {
|
||||
lockx.unlock();
|
||||
}
|
||||
}
|
||||
return ipv6.getPacket();
|
||||
} else {
|
||||
// System.out.println("miss:"+aseq.getSequence()+" "+sendMap.size());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class ResendChecker implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!closed) {
|
||||
|
||||
Collection<SendItem<V>> vals = sendMap.values();
|
||||
for (Iterator<SendItem<V>> iterator = vals.iterator(); iterator.hasNext();) {
|
||||
SendItem<V> sitm = (SendItem<V>) iterator.next();
|
||||
long current = System.nanoTime();
|
||||
if (current - sitm.getSendtime() > algorithm.getRTO()) {
|
||||
if (removeAtResend) {
|
||||
iterator.remove();
|
||||
long newWindow = sendWindowUsed.addAndGet((int) -sitm.getPacketLength() );
|
||||
algorithm.setCurrentWindowUsed(newWindow);
|
||||
tp.unpark();
|
||||
} else {
|
||||
sitm.setSendtime(current);
|
||||
}
|
||||
V pktr = sitm.getPacket();
|
||||
if (resendConsumer != null)
|
||||
resendConsumer.accept(pktr);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (closed) {
|
||||
checkerTask.cancel(false);
|
||||
// 清理资源
|
||||
if (closingConsumer != null) {
|
||||
for (SendItem<V> item : sendMap.values()) {
|
||||
@@ -229,6 +182,42 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
||||
}
|
||||
sendMap.clear();
|
||||
sendWindowUsed.set(0);
|
||||
|
||||
} else {
|
||||
|
||||
Set<Map.Entry<K,SendItem<V>>> vals = sendMap.entrySet();
|
||||
for (Iterator<Map.Entry<K,SendItem<V>>> iterator = vals.iterator(); iterator.hasNext(); ) {
|
||||
Map.Entry<K,SendItem<V>> entry = (Map.Entry<K,SendItem<V>>) iterator.next();
|
||||
SendItem<V> sitm=entry.getValue();
|
||||
long current = System.nanoTime();
|
||||
long ftime=current - sitm.getSendtime();
|
||||
if (ftime> algorithm.getRTO()) {
|
||||
|
||||
V pktr = sitm.getPacket();
|
||||
|
||||
if (removeAtResend) {
|
||||
SendItem<V> sitm2=sendMap.remove(entry.getKey());
|
||||
if(sitm2!=null) {
|
||||
if (resendConsumer != null)
|
||||
resendConsumer.accept(pktr);
|
||||
algorithm.putLoss(sitm2.getPacketLength(),ftime);
|
||||
long newWindow = sendWindowUsed.addAndGet((int) -sitm2.getPacketLength());
|
||||
algorithm.setCurrentWindowUsed(newWindow);
|
||||
tp.unpark();
|
||||
}
|
||||
} else {
|
||||
sitm.setSendtime(current);
|
||||
if (resendConsumer != null)
|
||||
resendConsumer.accept(pktr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@ package org.kne.cloud.network.congestion;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.kne.cloud.network.monitor.DelaySampler;
|
||||
import org.kne.concurrent.SpinLock;
|
||||
|
||||
public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCongestionAlgorithm {
|
||||
|
||||
// 可配置的时延膨胀比上下限 - Vegas2.0核心参数
|
||||
@@ -11,29 +14,26 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
||||
|
||||
private static final long BURST_TIME = 2000000L;
|
||||
private static final long BIAS = 1000000L;
|
||||
private static long MIN_WINDOW = 16384;
|
||||
private static long MIN_WINDOW = 8192;
|
||||
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
|
||||
private long MIN_RTTVAR = 30000000L;
|
||||
private volatile long RTTCurr = 1000000000L; // RTT
|
||||
private volatile long RTTMin = 1000000000L; // BaseRTT
|
||||
private volatile long RTTVar = 1000000000L;
|
||||
private volatile long RTTAvg = 1000000000L;
|
||||
private volatile long RTTAvg2 = 1000000000L; // 当前平滑RTT
|
||||
private volatile long RTTTotal = 0;
|
||||
private volatile long RTTCount = 0;
|
||||
private volatile long RTO = 1000000000L;
|
||||
|
||||
private RTTEstimator rttEstimator=new RTTEstimator();
|
||||
|
||||
private volatile long OWDTotal = 0;
|
||||
private volatile long OWDCount = 0;
|
||||
private volatile long OWDAvg2 = 1000000000L; // 当前平滑OWD
|
||||
private volatile long OWDMin = 1000000000L; // BaseRTT
|
||||
|
||||
private volatile long window = MIN_WINDOW;
|
||||
private volatile long window2 = MIN_WINDOW;
|
||||
private volatile long maxwindow = 99999999999L;
|
||||
|
||||
private final SpinLock slock=new SpinLock();
|
||||
|
||||
public Vegas2CongestionAlgorithm() {
|
||||
reset();
|
||||
}
|
||||
@@ -58,106 +58,13 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void putAck(long packetSize, long RTTns, long OWDup, boolean ecn) {
|
||||
if(RTTns<0) {
|
||||
throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
|
||||
}
|
||||
// 处理ECN信号 - 将其视为强烈的拥塞信号
|
||||
if (ecn) {
|
||||
// 当收到ECN时,更激进地减少窗口
|
||||
window2 = Math.max(0, window2 * 3 / 4);
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window2);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最小RTT(BaseRTT)
|
||||
if (RTTns <= RTTMin) {
|
||||
RTTMin = RTTns;
|
||||
} else {
|
||||
// 缓慢适应:当网络路径真正变化时,BaseRTT应能缓慢更新
|
||||
// 这里使用极慢的衰减因子,只有在持续观测到更低RTT时才快速更新
|
||||
RTTMin = (RTTMin * 999 + RTTns) / 1000;
|
||||
}
|
||||
|
||||
// 更新最小OWD(BaseOWD)
|
||||
if (OWDup <= OWDMin) {
|
||||
OWDMin = OWDup;
|
||||
} else {
|
||||
// 缓慢适应:当网络路径真正变化时,BaseRTT应能缓慢更新
|
||||
// 这里使用极慢的衰减因子,只有在持续观测到更低RTT时才快速更新
|
||||
OWDMin = (OWDMin * 999 + OWDup) / 1000;
|
||||
}
|
||||
|
||||
// 更新平滑RTT估计
|
||||
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - RTTns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + RTTns) / 8;
|
||||
|
||||
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);
|
||||
|
||||
RTTTotal += RTTns;
|
||||
RTTCount++;
|
||||
|
||||
OWDTotal += OWDup;
|
||||
OWDCount++;
|
||||
|
||||
long curr = System.nanoTime();
|
||||
// 每个RTT周期调整一次窗口(使用当前估计的RTT)
|
||||
if (curr - RTTstartTime > Math.max(BIAS, 2*RTTMin)) {
|
||||
long RTTCountx=RTTCount;
|
||||
if (RTTCountx > 0) {
|
||||
long currentRTT = RTTTotal / RTTCountx;
|
||||
//RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4; // 平滑当前RTT
|
||||
RTTAvg2=currentRTT;
|
||||
RTTTotal = 0;
|
||||
RTTCount = 0;
|
||||
}
|
||||
|
||||
long OWDCountx=OWDCount;
|
||||
if (OWDCountx > 0) {
|
||||
long currentOWD = OWDTotal / OWDCountx;
|
||||
OWDAvg2=currentOWD;
|
||||
OWDTotal = 0;
|
||||
OWDCount = 0;
|
||||
}
|
||||
|
||||
|
||||
// ================== Vegas2.0核心逻辑 ==================
|
||||
// 1. 计算时延膨胀比
|
||||
double delayRatio = (double) OWDAvg2 / (double) Math.max(BIAS, OWDMin);
|
||||
//System.out.println(delayRatio+" "+RTTAvg2/1000000.0+" "+RTTMin/1000000.0);
|
||||
// 2. 基于比值的窗口调整(取代原来的基于差值的调整)
|
||||
if (delayRatio > delayUpperBound) {
|
||||
// 时延过高:减小窗口,减少幅度与超标程度成正比
|
||||
window2 -= 4096;
|
||||
} else if (delayRatio < delayLowerBound) {
|
||||
// 时延过低:增大窗口,增加幅度与低于目标程度成正比
|
||||
window2 += 4096;
|
||||
} else {
|
||||
|
||||
}
|
||||
// ===================================================
|
||||
|
||||
|
||||
|
||||
|
||||
updateWindowSize();
|
||||
RTTstartTime = curr;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAck(long packetSize, long RTTns, boolean ecn) {
|
||||
if(RTTns<0) {
|
||||
throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
|
||||
}
|
||||
this.RTTCurr=RTTns;
|
||||
// 处理ECN信号 - 将其视为强烈的拥塞信号
|
||||
if (ecn) {
|
||||
// 当收到ECN时,更激进地减少窗口
|
||||
@@ -167,34 +74,25 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最小RTT(BaseRTT)
|
||||
if (RTTns <= RTTMin) {
|
||||
RTTMin = RTTns;
|
||||
} else {
|
||||
// 缓慢适应:当网络路径真正变化时,BaseRTT应能缓慢更新
|
||||
// 这里使用极慢的衰减因子,只有在持续观测到更低RTT时才快速更新
|
||||
RTTMin = (RTTMin * 999 + RTTns) / 1000;
|
||||
}
|
||||
|
||||
// 更新平滑RTT估计
|
||||
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - RTTns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + RTTns) / 8;
|
||||
|
||||
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);
|
||||
rttEstimator.putRTT(RTTns);
|
||||
|
||||
RTTTotal += RTTns;
|
||||
RTTCount++;
|
||||
|
||||
if(slock.tryLock())try {
|
||||
long curr = System.nanoTime();
|
||||
// 每个RTT周期调整一次窗口(使用当前估计的RTT)
|
||||
if (curr - RTTstartTime > Math.max(BIAS, 2*RTTMin)) {
|
||||
long RTTCountx=RTTCount;
|
||||
if (curr - RTTstartTime > Math.max(BIAS, 2 * RTTMin)) {
|
||||
rttEstimator.update();
|
||||
RTTMin = rttEstimator.getBaseRTT();
|
||||
|
||||
|
||||
long RTTCountx = RTTCount;
|
||||
if (RTTCountx > 0) {
|
||||
long currentRTT = RTTTotal / RTTCountx;
|
||||
//RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4; // 平滑当前RTT
|
||||
RTTAvg2=currentRTT;
|
||||
RTTAvg2 = currentRTT;
|
||||
RTTTotal = 0;
|
||||
RTTCount = 0;
|
||||
}
|
||||
@@ -206,24 +104,23 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
||||
// 2. 基于比值的窗口调整(取代原来的基于差值的调整)
|
||||
if (delayRatio > delayUpperBound) {
|
||||
// 时延过高:减小窗口,减少幅度与超标程度成正比
|
||||
window2 -= 4096;
|
||||
window2 = window2 - 4096;
|
||||
} else if (delayRatio < delayLowerBound) {
|
||||
// 时延过低:增大窗口,增加幅度与低于目标程度成正比
|
||||
window2 += 4096;
|
||||
window2 = window2 + 4096;
|
||||
} else {
|
||||
|
||||
//window2=window2+4096
|
||||
}
|
||||
// ===================================================
|
||||
|
||||
|
||||
|
||||
|
||||
updateWindowSize();
|
||||
RTTstartTime = curr;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}finally{
|
||||
slock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,12 +142,12 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
public void putLoss(long packetSize, long lossns) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
return rttEstimator.getRTO();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -269,12 +166,14 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
||||
}
|
||||
|
||||
public long getBaseRTT() {
|
||||
return RTTMin;
|
||||
return rttEstimator.getBaseRTT();
|
||||
}
|
||||
|
||||
public long getCurrentRTT() {
|
||||
public long getAvgRTT() {
|
||||
return RTTAvg2;
|
||||
}
|
||||
public long getCurrentRTT() {
|
||||
return RTTCurr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpperDelayBound(double upper) {
|
||||
@@ -295,4 +194,19 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
||||
return "Vegas2";
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getUpperDelayBound() {
|
||||
return delayUpperBound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLowerDelayBound() {
|
||||
return delayLowerBound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBurstLimit() {
|
||||
return burstLimit;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,11 +15,18 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
||||
private SRv6Router srv6Router;
|
||||
private final boolean loopback;
|
||||
|
||||
private final boolean filter;
|
||||
|
||||
|
||||
public AbstractIPv6NetworkLink(boolean loopback) {
|
||||
super();
|
||||
this.loopback = loopback;
|
||||
this.filter = false;
|
||||
}
|
||||
public AbstractIPv6NetworkLink(boolean loopback, boolean filter) {
|
||||
super();
|
||||
this.loopback = loopback;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public SRv6Router getSrv6Router() {
|
||||
@@ -63,6 +70,8 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
||||
}
|
||||
|
||||
private BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> receiveConsumer;
|
||||
|
||||
private Supplier<Long> costSupplier;
|
||||
@Override
|
||||
public void setReceiveConsumer(BiConsumer<IPv6NetworkLink,Supplier< IPv6Packet>> receiveConsumer) {
|
||||
this.receiveConsumer = receiveConsumer;
|
||||
@@ -73,6 +82,14 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
||||
return loopback;
|
||||
}
|
||||
|
||||
public Supplier<Long> getCostSupplier() {
|
||||
return costSupplier;
|
||||
}
|
||||
|
||||
public void setCostSupplier(Supplier<Long> costSupplier) {
|
||||
this.costSupplier = costSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RouteItem> getRouteItems() {
|
||||
List<RouteItem> rlist = new ArrayList<>();
|
||||
@@ -86,16 +103,21 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
|
||||
Neighbor addresses = (Neighbor) iteratorx.next();
|
||||
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
|
||||
addresses.getAddress().getAddress(), this,RouteItem.SRv6_ENDXSID, 0, 128, null, "D");
|
||||
addresses.getAddress().getAddress(), this,RouteItem.SRv6_ENDXSID, 0, 128, costSupplier, "D");
|
||||
rlist.add(ri);
|
||||
|
||||
RouteItem ris = new RouteItem(addresses.getLocator(),
|
||||
addresses.getLocator().getAddress(), this, RouteItem.SRv6_ENDSID, 13, 128,
|
||||
null, "D");
|
||||
costSupplier, "D");
|
||||
rlist.add(ris);
|
||||
|
||||
}
|
||||
}
|
||||
return rlist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFilter() {
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@ public final class IPv6Address implements Comparable<IPv6Address> {
|
||||
((long)(bytes[15] & 0xFF));
|
||||
}
|
||||
|
||||
public IPv6Address(String string) throws UnknownHostException {
|
||||
this((Inet6Address) Inet6Address.getByName(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从两个long创建IPv6地址
|
||||
*/
|
||||
|
||||
@@ -67,7 +67,16 @@ public class IPv6AddressGroup implements Comparable<IPv6AddressGroup>{
|
||||
prefixLength=in.read();
|
||||
}
|
||||
public boolean checkMatch(IPv6Address address2) {
|
||||
return address2.equals(address.maskWith(IPv6Address.createMask(prefixLength)));
|
||||
IPv6Address cmsk= IPv6Address.createMask(prefixLength);
|
||||
return address2.maskWith(cmsk).equals(address.maskWith(cmsk));
|
||||
}
|
||||
/**
|
||||
* 返回裁剪后的路由表地址(主机位清零)。
|
||||
* 例如 2001:db8:1::100/64 → 2001:db8:1::/64
|
||||
*/
|
||||
public IPv6AddressGroup toNetworkRoute() {
|
||||
IPv6Address mask = IPv6Address.createMask(prefixLength);
|
||||
IPv6Address maskedAddr = address.maskWith(mask);
|
||||
return new IPv6AddressGroup(maskedAddr, prefixLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,4 +30,5 @@ public interface IPv6NetworkLink {
|
||||
public void addIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||
public void removeIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||
|
||||
public boolean isFilter();
|
||||
}
|
||||
|
||||
@@ -1378,7 +1378,7 @@ public class IPv6Packet extends NetworkPacket {
|
||||
// 重路由计数器
|
||||
private AtomicInteger rerouteCounter = new AtomicInteger(0);
|
||||
|
||||
public AtomicInteger getRerouteCounter() {
|
||||
public AtomicInteger getRouteCounter() {
|
||||
return rerouteCounter;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
||||
public static final String DIRECT="Direct";
|
||||
public static final String SRv6_ENDSID="SRv6 ENDSID";
|
||||
public static final String SRv6_ENDXSID="SRv6 ENDXSID";
|
||||
public static final String KLALB_SRv6 = "KLALB_SRv6";
|
||||
|
||||
private IPv6AddressGroup destination;
|
||||
private IPv6Address nexthop;
|
||||
@@ -39,7 +40,7 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
||||
public RouteItem(IPv6AddressGroup destination, IPv6Address nexthop, IPv6NetworkLink destlink, String proto, int pre,
|
||||
long cost,String flag) {
|
||||
super();
|
||||
this.destination = destination;
|
||||
this.destination = destination.toNetworkRoute();
|
||||
this.nexthop = nexthop;
|
||||
this.destlink = destlink;
|
||||
this.proto = proto;
|
||||
@@ -50,7 +51,7 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
||||
public RouteItem(IPv6AddressGroup destination, IPv6Address nexthop, IPv6NetworkLink destlink, String proto, int pre,
|
||||
long cost,Supplier<Long> costSupplier,String flag) {
|
||||
super();
|
||||
this.destination = destination;
|
||||
this.destination = destination.toNetworkRoute();
|
||||
this.nexthop = nexthop;
|
||||
this.destlink = destlink;
|
||||
this.proto = proto;
|
||||
|
||||
@@ -17,14 +17,8 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -67,7 +61,7 @@ public class KLALBController {
|
||||
public HighAccuracyClock getClock() {
|
||||
return clock;
|
||||
}
|
||||
private final long TIME_WINDOW=2000000000L;
|
||||
private final long TIME_WINDOW=30000000000L;
|
||||
private SpeedAndTrafficMonitorDataImpl linkMonitor = new SpeedAndTrafficMonitorDataImpl(
|
||||
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100,TIME_WINDOW ),
|
||||
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "down", 100, TIME_WINDOW));
|
||||
@@ -86,7 +80,7 @@ public class KLALBController {
|
||||
private static final boolean debug=false;
|
||||
private static final boolean showpacket = false;
|
||||
|
||||
private static final int PREFIX = 128;// 112
|
||||
private static final int PREFIX = 128;
|
||||
private static final int DISCOVERY_PORT = 4569;
|
||||
|
||||
private static List<IPMulticastDiscovery> ipmd = new ArrayList<>();
|
||||
@@ -104,23 +98,9 @@ public class KLALBController {
|
||||
public List<InetAddress> getDnsAddresses() {
|
||||
return dnsAddresses;
|
||||
}
|
||||
private ScheduledExecutorService scheduleTimer=Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(),new ThreadFactory() {
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return ThreadTool.makeVDaemonThreadIfSupport("计时器线程", r);
|
||||
}
|
||||
});
|
||||
|
||||
public ScheduledExecutorService getScheduleTimer() {
|
||||
return scheduleTimer;
|
||||
}
|
||||
|
||||
private Timer twk = new Timer("网卡检测扫描计时器", true);
|
||||
|
||||
|
||||
|
||||
private TimerTask tsk1 = new TimerTask() {
|
||||
private Runnable tsk1 = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -306,7 +286,7 @@ public class KLALBController {
|
||||
return srv6Router.getLocator().getAddress().toInet6Address().equals(inetAddress);
|
||||
}
|
||||
|
||||
private TimerTask tsk2 = new TimerTask() {
|
||||
private Runnable tsk2 = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -634,7 +614,8 @@ public class KLALBController {
|
||||
|
||||
private void loadSRv6ProtocolStack(IPv6AddressGroup selfx, boolean enableVirtualAdapter) {
|
||||
networkInterfaceManager.getInetAddressesExcept().add(selfx.getAddress().toInet6Address());
|
||||
srv6Router = new SRv6Router(selfx, clock);
|
||||
IPv6AddressGroup group=new IPv6AddressGroup(selfx.getAddress(),32);
|
||||
srv6Router = new SRv6Router(selfx,group, clock);
|
||||
if(configItem!=null) {
|
||||
srv6Router.setPerformanceStrategy(PerformanceStrategy.fromDescription(configItem.getPerformanceStrategy()));
|
||||
srv6Router.setDeviceName(configItem.getDeviceName());
|
||||
@@ -653,8 +634,7 @@ public class KLALBController {
|
||||
if (enableTUN) {
|
||||
Thread t=new Thread(()->{
|
||||
try {
|
||||
IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name.trim(),
|
||||
new IPv6AddressGroup(srv6Router.getLocator().getAddress(), 32), SRv6Router.MTU, dnsAddresses);
|
||||
IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name.trim(),group, SRv6Router.MTU, dnsAddresses);
|
||||
tunlink.setMonitor(datatMonitor);
|
||||
// srv6Router.getLinkTabel().add(tunlink);
|
||||
srv6Router.getinLoopback().setFallbackLink(tunlink);
|
||||
@@ -686,7 +666,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 +698,7 @@ public class KLALBController {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
});*/
|
||||
nvc2 = new NTPv4Protocol(context, new MultiProtocolSocketAddress("udp","0.0.0.0",0));
|
||||
|
||||
System.out.println(" Loaded: NTP Module");
|
||||
@@ -734,8 +714,8 @@ public class KLALBController {
|
||||
private void loadController() {
|
||||
this.apiServer = new KLALBRoutingProtocolAPIServer(routingProtocol, this);
|
||||
this.apiClient = new KLALBRoutingProtocolAPIClient(routingProtocol);
|
||||
twk.schedule(tsk1, 5000, 5000);
|
||||
twk.schedule(tsk2, 5000, 5000);
|
||||
KLALBScheduler.getScheduler().scheduleAtFixedRate(tsk1, 5000, 5000,TimeUnit.MILLISECONDS);
|
||||
KLALBScheduler.getScheduler().scheduleAtFixedRate(tsk2, 5000, 5000,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public KLALBController() {
|
||||
@@ -753,17 +733,12 @@ public class KLALBController {
|
||||
}
|
||||
|
||||
protected void initKLALB(boolean enableVirtualAdapter, IPv6AddressGroup selfg) {
|
||||
ThreadTool.makeVDaemonThread("线路性能采样线程", ()->{
|
||||
while(true) {
|
||||
KLALBScheduler.getScheduler().scheduleWithFixedDelay( ()->{
|
||||
linkMonitor.update();
|
||||
},1,1,TimeUnit.MILLISECONDS);
|
||||
KLALBScheduler.getScheduler().scheduleWithFixedDelay( ()->{
|
||||
datatMonitor.update();
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
},1,1,TimeUnit.MILLISECONDS);
|
||||
loadSRv6ProtocolStack(selfg, enableVirtualAdapter);
|
||||
loadController();
|
||||
}
|
||||
@@ -856,9 +831,8 @@ public class KLALBController {
|
||||
return srv6Router;
|
||||
}
|
||||
|
||||
private Timer trtr = new Timer("路由表刷新计时器", true);
|
||||
{
|
||||
trtr.scheduleAtFixedRate(new TimerTask() {
|
||||
KLALBScheduler.getScheduler().scheduleAtFixedRate(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -869,9 +843,9 @@ public class KLALBController {
|
||||
srv6Router.updateRouteTabel();
|
||||
}
|
||||
}
|
||||
}, 100, 100);
|
||||
}, 100, 100, TimeUnit.MILLISECONDS);
|
||||
|
||||
trtr.scheduleAtFixedRate(new TimerTask() {
|
||||
KLALBScheduler.getScheduler().scheduleAtFixedRate(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -880,7 +854,7 @@ public class KLALBController {
|
||||
}
|
||||
|
||||
}
|
||||
}, 10, 10);
|
||||
}, 1, 1,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public IPv6Packet createPacketToAddress(IPv6Address addr, int flowlabel, IPv6Packet.IPv6Payload packet) {
|
||||
|
||||
@@ -13,13 +13,15 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jctools.queues.MpscArrayQueue;
|
||||
import org.jctools.queues.varhandle.MpscVarHandleArrayQueue;
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.clock.NTPTimestamps;
|
||||
import org.kne.cloud.clock.ReliabilityBackoffTimeClock;
|
||||
@@ -31,17 +33,8 @@ import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.CongestionAlgorithms;
|
||||
import org.kne.cloud.network.congestion.DetnetCongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||
import org.kne.cloud.network.ipv6.ControlledIPv6NetworkLink;
|
||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||
import org.kne.cloud.network.ipv6.IPv6HopByHopTLV;
|
||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||
import org.kne.cloud.network.ipv6.*;
|
||||
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6HopByHopHeader;
|
||||
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
||||
import org.kne.cloud.network.ipv6.KLALBOAMHopByHopTLV;
|
||||
import org.kne.cloud.network.ipv6.KLALBPassportHopByHopTLV;
|
||||
import org.kne.cloud.network.ipv6.Neighbor;
|
||||
import org.kne.cloud.network.ipv6.PostcardEntry;
|
||||
import org.kne.cloud.network.ipv6.RouteItem;
|
||||
import org.kne.cloud.network.monitor.CostSupplierFactory;
|
||||
import org.kne.cloud.network.monitor.DelayMonitorData;
|
||||
import org.kne.cloud.network.monitor.LinkStatus;
|
||||
@@ -149,6 +142,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
this.addressGroup = address;
|
||||
monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
||||
name=kpl.toString();
|
||||
setCostSupplier( CostSupplierFactory.owdSupplier(monitor));
|
||||
}
|
||||
|
||||
private KLALBRemoteLink(KLALBController controller, MultiProtocolSocketAddress mpa, MultiProtocolSocketAddress bindaddr, IPv6AddressGroup address) {
|
||||
@@ -164,6 +158,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
} else {
|
||||
name=bindaddr.toString() + "→" + mpa.toString();
|
||||
}
|
||||
setCostSupplier( CostSupplierFactory.owdSupplier( monitor));
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +184,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
|
||||
private class RemoteSender implements Runnable {
|
||||
|
||||
private MpscArrayQueue<KLALBPacket> sendQueue = new MpscArrayQueue<KLALBPacket>(8192);
|
||||
private MpscVarHandleArrayQueue<KLALBPacket> sendQueue = new MpscVarHandleArrayQueue<KLALBPacket>(8192);
|
||||
private WatchDogTimer watchdog = new WatchDogTimer(400000000L);
|
||||
|
||||
private ThreadParker tlock = new ThreadParker();
|
||||
@@ -283,12 +278,12 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
sendLock.lock();
|
||||
try {
|
||||
kplink.flush();
|
||||
watchdog.feed();
|
||||
}finally {
|
||||
sendLock.unlock();
|
||||
}
|
||||
watchdog.feed();
|
||||
}
|
||||
tlock.parkNanos(10000000L);
|
||||
tlock.parkNanos(1000000L);
|
||||
|
||||
}
|
||||
} catch (StreamCorruptedException sce) {
|
||||
@@ -568,20 +563,17 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
private ThreadParker tpk=new ThreadParker();
|
||||
|
||||
private StateManager stateManager;
|
||||
private MonitorUpdater monitorUpdater;
|
||||
private ScheduledFuture<?> monitorUpdater;
|
||||
private class MonitorUpdater implements Runnable{
|
||||
@Override
|
||||
public void run() {
|
||||
while (!closed) {
|
||||
if(closed) {
|
||||
monitorUpdater.cancel(false);
|
||||
}else{
|
||||
status.updateReliability();
|
||||
if(status.getState()!=LinkStatus.DOWN) {
|
||||
monitor.update();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -753,8 +745,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
|
||||
protected void startIO() {
|
||||
stateManager=new StateManager();
|
||||
monitorUpdater=new MonitorUpdater();
|
||||
ThreadTool.makeVDaemonThread("线路性能采样线程", monitorUpdater).start();
|
||||
monitorUpdater=KLALBScheduler.getScheduler().scheduleWithFixedDelay(new MonitorUpdater(),1,1, TimeUnit.MILLISECONDS);
|
||||
ThreadTool.makeVDaemonThread("远程线路状态线程", stateManager).start();
|
||||
|
||||
}
|
||||
@@ -896,6 +887,8 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
sendWindow.put(val, pack);
|
||||
//}
|
||||
}
|
||||
}else {
|
||||
System.out.println(hop);
|
||||
}
|
||||
|
||||
sendIPv6PacketToLink(pack, val);
|
||||
@@ -944,28 +937,6 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
return (!isClosed()) && (status.getState() == LinkStatus.UP) ;
|
||||
}
|
||||
|
||||
/*@Override
|
||||
public List<RouteItem> getRouteItems() {
|
||||
List<RouteItem> rlist = new ArrayList<>();
|
||||
|
||||
if(isUp()) {
|
||||
|
||||
|
||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext(); ) {
|
||||
Neighbor addresses = (Neighbor) iteratorx.next();
|
||||
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
|
||||
addresses.getAddress().getAddress(), this, RouteItem.SRv6_ENDXSID, 0, 128, CostSupplierFactory.expectedDelaySupplier((DelayMonitorData) addresses.getMonitor(), status, algorithm::getRTO), "D");
|
||||
rlist.add(ri);
|
||||
|
||||
if (addresses.getLocator() != null) {
|
||||
RouteItem ris = new RouteItem(addresses.getLocator(), addresses.getLocator().getAddress(), this,
|
||||
RouteItem.SRv6_ENDSID, 13, 128, CostSupplierFactory.expectedDelaySupplier((DelayMonitorData) addresses.getMonitor(), status, algorithm::getRTO), "D");
|
||||
rlist.add(ris);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rlist;
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void setCongressCondition(Lock lock, Condition condition) {
|
||||
@@ -973,14 +944,32 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
||||
sendWindow.setCongressCondition(lock, condition);
|
||||
}
|
||||
|
||||
public void onPostcardReceive(PostcardEntry postcard) {
|
||||
public void onPostcardReceive(IPv6NetworkLink linkfrom,PostcardEntry postcard) {
|
||||
long deltaxnanos = (long) (postcard.getTimestampDeltaLong() * 1000000000.0 / (1L << 32));
|
||||
if (deltaxnanos > 0) {
|
||||
Long128 curr= sysclk.getCurrentTimeNanos();
|
||||
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||
NTPTimestamps.inferNtp64To128(postcard.getTimestampBase(), sysclk.getCurrentTimeNTP128()));
|
||||
NTPTimestamps.inferNtp64To128(postcard.getTimestampBase(),NTPTimestamps.nanosToNtp128BitTimestamp(curr)));
|
||||
long rtt=curr.subtract(psnd).longValue();
|
||||
if (deltaxnanos >= 0) {
|
||||
monitor.recordUploadDelay(deltaxnanos);
|
||||
}
|
||||
sendWindow.ack(postcard.getPacketUUID(),false,deltaxnanos);
|
||||
if(linkfrom instanceof KLALBRemoteLink ){
|
||||
long rtt2=deltaxnanos+((KLALBRemoteLink) linkfrom).getMonitor().getInDelayMin();
|
||||
|
||||
if(rtt2<0) {
|
||||
if(rtt<0) {
|
||||
rtt=0;
|
||||
}
|
||||
sendWindow.ack(postcard.getPacketUUID(), rtt, false);
|
||||
}else {
|
||||
sendWindow.ack(postcard.getPacketUUID(), rtt2, false);
|
||||
}
|
||||
}else {
|
||||
if(rtt<0) {
|
||||
rtt=0;
|
||||
}
|
||||
sendWindow.ack(postcard.getPacketUUID(), rtt, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.kne.cloud.network.klalb;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class KLALBScheduler {
|
||||
private static final ScheduledExecutorService scheduler;
|
||||
static {
|
||||
scheduler= Executors.newScheduledThreadPool( Runtime.getRuntime().availableProcessors(),
|
||||
(r) -> {
|
||||
Thread t = new Thread(r, "KLALB-Scheduler");
|
||||
t.setDaemon(true); // 守护线程,不阻止 JVM 退出
|
||||
return t;
|
||||
});
|
||||
}
|
||||
public static ScheduledExecutorService getScheduler(){
|
||||
return scheduler;
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,6 @@ import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jctools.counters.CountersFactory;
|
||||
import org.jctools.counters.FixedSizeStripedLongCounter;
|
||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||
|
||||
@@ -434,7 +432,5 @@ public static String parseAbbrIPv6(String IPv6Str) {
|
||||
}
|
||||
|
||||
|
||||
public static FixedSizeStripedLongCounter createCounter() {
|
||||
return CountersFactory.createFixedSizeStripedCounter(Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.net.SocketException;
|
||||
|
||||
import org.kne.cloud.network.VirtualDatagramSocket;
|
||||
import org.kne.cloud.network.VirtualDatagramSocketImpl;
|
||||
import org.pcap4j.core.Inets;
|
||||
|
||||
public class KLALBVirtualDatagramSocket extends VirtualDatagramSocket {
|
||||
|
||||
|
||||
@@ -118,46 +118,50 @@ public class StreamChannelKLALBPacketLink extends AbstractKLALBPacketLink implem
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 增加两个 ThreadLocal 静态变量,用于复用 4 字节的长度头
|
||||
private static final ThreadLocal<ByteBuffer> SIZE_WRITE_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(4));
|
||||
private static final ThreadLocal<ByteBuffer> SIZE_READ_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(4));
|
||||
|
||||
@Override
|
||||
public void writePacket(ByteBuffer kp) throws IOException {
|
||||
ByteBuffer szeWrite=NetworkPacket.bufferAllocator.allocate(4);
|
||||
szeWrite.limit(4);
|
||||
//szeWrite.clear();
|
||||
// 1. 获取并清空缓存的 4 字节 buffer
|
||||
ByteBuffer szeWrite = SIZE_WRITE_BUFFER.get();
|
||||
szeWrite.clear();
|
||||
|
||||
// 2. 写入长度并翻转
|
||||
szeWrite.putInt(kp.limit());
|
||||
szeWrite.flip();
|
||||
KLALBVirtualSocketChannel obj = null;
|
||||
writableChannel.write(new ByteBuffer[] {szeWrite,kp});
|
||||
|
||||
// 3. 发送
|
||||
writableChannel.write(new ByteBuffer[] {szeWrite, kp});
|
||||
checkflush();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ByteBuffer readPacket() throws IOException {
|
||||
|
||||
ByteBuffer szeRead=NetworkPacket.bufferAllocator.allocate(4);
|
||||
timeoutTimer=System.nanoTime();
|
||||
timerenabled=true;
|
||||
ByteBuffer kp;
|
||||
// 1. 获取并清空缓存的 4 字节 buffer
|
||||
ByteBuffer szeRead = SIZE_READ_BUFFER.get();
|
||||
szeRead.clear();
|
||||
szeRead.limit(4);
|
||||
//szeRead.clear();
|
||||
|
||||
timeoutTimer = System.nanoTime();
|
||||
timerenabled = true;
|
||||
ByteBuffer kp;
|
||||
|
||||
try {
|
||||
KNEChannels.readFully(readableChannel,szeRead);
|
||||
// 2. 读取长度头
|
||||
KNEChannels.readFully(readableChannel, szeRead);
|
||||
szeRead.flip();
|
||||
int size=szeRead.getInt(0);
|
||||
kp=NetworkPacket.bufferAllocator.allocate(size);
|
||||
int size = szeRead.getInt(0);
|
||||
|
||||
// 3. 分配真正的数据区(这里如果是高频,建议后续也可以池化,不过现在是按需大小分配)
|
||||
kp = NetworkPacket.bufferAllocator.allocate(size);
|
||||
kp.limit(size);
|
||||
KNEChannels.readFully(readableChannel, kp);
|
||||
kp.flip();
|
||||
return kp;
|
||||
}finally {
|
||||
timerenabled=false;
|
||||
} finally {
|
||||
timerenabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@ import java.awt.*;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.event.*;
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
@@ -16,6 +17,7 @@ import javax.swing.border.LineBorder;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import com.sun.management.OperatingSystemMXBean;
|
||||
import org.jfree.chart.plot.dial.*;
|
||||
import org.jfree.data.general.DefaultValueDataset;
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
@@ -37,8 +39,7 @@ import org.kne.ui.YScrollPane;
|
||||
public class KLALBStateGUI3 extends XFrame {
|
||||
|
||||
// ==================== 定时任务相关 ====================
|
||||
private TimerTask tsk, tsk2, tsk3, tsk4, tsk5; // 各种定时任务
|
||||
private Timer t, t2, t3; // 定时器
|
||||
private ScheduledFuture<?> tsk, tsk2, tsk3, tsk4, tsk5; // 各种定时任务
|
||||
|
||||
// ==================== 系统托盘相关 ====================
|
||||
private SystemTray st; // 系统托盘
|
||||
@@ -57,7 +58,8 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
private DefaultValueDataset backplanePPS;
|
||||
private DefaultValueDataset backplaneECNRate;
|
||||
private DefaultValueDataset backplaneLossRate;
|
||||
|
||||
private DefaultValueDataset CPUload;
|
||||
private DefaultValueDataset RAMusage;
|
||||
// ==================== 仪表盘文本标注 ====================
|
||||
private DialTextAnnotation upSpeedText; // 上行速度文本标注
|
||||
private DialTextAnnotation downSpeedText; // 下行速度文本标注
|
||||
@@ -67,6 +69,8 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
private DialTextAnnotation backplanePPSText;
|
||||
private DialTextAnnotation backplaneECNRateText;
|
||||
private DialTextAnnotation backplaneLossRateText;
|
||||
private DialTextAnnotation CPUloadText;
|
||||
private DialTextAnnotation RAMusageText;
|
||||
|
||||
// ==================== UI组件 ====================
|
||||
private YScrollPane ysp, yspc; // 可垂直滚动的面板
|
||||
@@ -434,6 +438,22 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
backplaneLossRateText = lossRate1.getTextAnnotation();
|
||||
|
||||
dashs.add(lossRate1);
|
||||
|
||||
// CPU
|
||||
CPUload = new DefaultValueDataset(0);
|
||||
DialPanel cload=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("cpuload"), CPUload, null, Color.BLUE, new Color(0, 0, 127));
|
||||
cload.addGradientRanges(UIEnv.RANGE_1);
|
||||
CPUloadText = cload.getTextAnnotation();
|
||||
|
||||
dashs.add(cload);
|
||||
|
||||
// RAM
|
||||
RAMusage = new DefaultValueDataset(0);
|
||||
DialPanel ruse=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("ramusage"), RAMusage, null, Color.BLUE, new Color(0, 0, 127));
|
||||
ruse.addGradientRanges(UIEnv.RANGE_1);
|
||||
RAMusageText = ruse.getTextAnnotation();
|
||||
|
||||
dashs.add(ruse);
|
||||
}
|
||||
|
||||
|
||||
@@ -705,10 +725,6 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
* 初始化定时器
|
||||
*/
|
||||
private void initTimers(KLALBController kc) {
|
||||
t3 = new Timer("监视器刷新线程", true);
|
||||
t2 = new Timer("仪表盘刷新线程", true);
|
||||
t = new Timer("状态刷新线程", true);
|
||||
|
||||
// 创建刷新任务
|
||||
createRefreshTask(kc, ysp);
|
||||
}
|
||||
@@ -1322,9 +1338,9 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
private void createRefreshTask(KLALBController kc, YScrollPane ysp) {
|
||||
// 线路状态刷新任务
|
||||
if (tsk != null) {
|
||||
tsk.cancel();
|
||||
tsk.cancel(false);
|
||||
}
|
||||
tsk = new TimerTask() {
|
||||
tsk =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isVisible()) {
|
||||
@@ -1382,28 +1398,27 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
ysp.updateScrool();
|
||||
}
|
||||
}
|
||||
};
|
||||
t.scheduleAtFixedRate(tsk, 1000, 1000);
|
||||
}, 1000, 1000, TimeUnit.MILLISECONDS);
|
||||
|
||||
// 仪表盘数据刷新任务
|
||||
if (tsk2 != null) {
|
||||
tsk2.cancel();
|
||||
tsk2.cancel(false);
|
||||
}
|
||||
tsk2 = new TimerTask() {
|
||||
tsk2 =KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isVisible()) {
|
||||
updateDashboardData(kc);
|
||||
}
|
||||
}
|
||||
};
|
||||
t2.scheduleAtFixedRate(tsk2, 100, 100);
|
||||
}, 100, 100,TimeUnit.MILLISECONDS);
|
||||
|
||||
|
||||
// 网络图刷新任务
|
||||
if (tsk5 != null) {
|
||||
tsk5.cancel();
|
||||
tsk5.cancel(false);
|
||||
}
|
||||
tsk5 = new TimerTask() {
|
||||
tsk5 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isVisible()) {
|
||||
@@ -1415,8 +1430,7 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
graph.revalidate();
|
||||
}
|
||||
}
|
||||
};
|
||||
t.scheduleAtFixedRate(tsk5, 1000, 1000);
|
||||
}, 1000, 1000,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1425,29 +1439,29 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
private void updateDashboardData(KLALBController kc) {
|
||||
// 更新上行速度
|
||||
double outload = kc.getLinkMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax();
|
||||
if (Double.isFinite(outload)) {
|
||||
upSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getOutSpeed()) + "/s");
|
||||
if (Double.isFinite(outload)) {
|
||||
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
||||
}
|
||||
|
||||
// 更新下行速度
|
||||
double inload = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax();
|
||||
if (Double.isFinite(inload)) {
|
||||
downSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getInSpeed()) + "/s");
|
||||
if (Double.isFinite(inload)) {
|
||||
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
||||
}
|
||||
|
||||
// 更新上行包速率
|
||||
double outPPSload = kc.getLinkMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax();
|
||||
if (Double.isFinite(outPPSload)) {
|
||||
upPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getOutPPS()) + "PPS");
|
||||
if (Double.isFinite(outPPSload)) {
|
||||
upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
|
||||
}
|
||||
|
||||
// 更新下行包速率
|
||||
double inPPSload = kc.getLinkMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax();
|
||||
if (Double.isFinite(inPPSload)) {
|
||||
downPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getInPPS()) + "PPS");
|
||||
if (Double.isFinite(inPPSload)) {
|
||||
downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
|
||||
}
|
||||
|
||||
@@ -1479,33 +1493,54 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
if(router!=null) {
|
||||
// 更新背板延迟
|
||||
double backplaneTimev = router.getBackplaneTime()* 100.0/100000.0;
|
||||
if (Double.isFinite(backplaneTimev)) {
|
||||
backplaneDelayText.setLabel(KLALBUtils.convertUintNanoDefalut(router.getBackplaneTime()) + "s");
|
||||
if (Double.isFinite(backplaneTimev)) {
|
||||
backplaneDelay.setValue(Math.min(backplaneDelay.getValue().doubleValue() * 0.98 + backplaneTimev * 0.02, 101.0));
|
||||
}
|
||||
|
||||
// 更新背板转发率
|
||||
double backplanePPSv = router.getBackplanePPS() * 100.0 / router.getBackplanePPSMax();
|
||||
if (Double.isFinite(backplanePPSv)) {
|
||||
backplanePPSText.setLabel(KLALBUtils.convertUintDefalut(router.getBackplanePPS()) + "PPS");
|
||||
if (Double.isFinite(backplanePPSv)) {
|
||||
backplanePPS.setValue(Math.min(backplanePPS.getValue().doubleValue() * 0.98 + backplanePPSv * 0.02, 101.0));
|
||||
}
|
||||
|
||||
// 更新背板ECN率
|
||||
double backplaneECNv = router.getECNRate() * 100.0 ;
|
||||
if (Double.isFinite(backplaneECNv)) {
|
||||
backplaneECNRateText.setLabel(String.format("%.1f",backplaneECNv) + "%");
|
||||
if (Double.isFinite(backplaneECNv)) {
|
||||
backplaneECNRate.setValue(Math.min(backplaneECNRate.getValue().doubleValue() * 0.98 + backplaneECNv * 0.02, 101.0));
|
||||
}
|
||||
|
||||
// 更新背板ECN率
|
||||
double backplaneLossv = router.getLossRate() * 100.0 ;
|
||||
if (Double.isFinite(backplaneLossv)) {
|
||||
backplaneLossRateText.setLabel(String.format("%.1f",backplaneLossv) + "%");
|
||||
if (Double.isFinite(backplaneLossv)) {
|
||||
backplaneLossRate.setValue(Math.min(backplaneLossRate.getValue().doubleValue() * 0.98 + backplaneLossv * 0.02, 101.0));
|
||||
}
|
||||
}
|
||||
|
||||
// 更新CPU
|
||||
OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||
double sys=osBean.getCpuLoad();
|
||||
double proc=osBean.getProcessCpuLoad();
|
||||
double load = proc/(1-sys+proc)* 100.0 ;
|
||||
if (Double.isFinite(load)) {
|
||||
CPUload.setValue(Math.min(CPUload.getValue().doubleValue() * 0.98 + load * 0.02, 101.0));
|
||||
}
|
||||
CPUloadText.setLabel(String.format("%.1f",load) + "%");
|
||||
|
||||
|
||||
// 更新RAM
|
||||
long max=Runtime.getRuntime().maxMemory();
|
||||
long free=Runtime.getRuntime().freeMemory();
|
||||
double ramUsage = (double) (max - free) /max* 100.0 ;
|
||||
if (Double.isFinite(ramUsage)) {
|
||||
RAMusage.setValue(Math.min(RAMusage.getValue().doubleValue() * 0.98 + ramUsage * 0.02, 101.0));
|
||||
}
|
||||
RAMusageText.setLabel(KLALBUtils.convertIBUint(max- free)+"/"+KLALBUtils.convertIBUint(max ) );
|
||||
|
||||
|
||||
// 更新在线设备数
|
||||
String contt = Long.toString(kc.getIpv6Router().getKlalbRouteProtol().getDevicesFound());
|
||||
if (!contt.equals(devicesOnline.getText())) {
|
||||
@@ -1764,7 +1799,7 @@ public class KLALBStateGUI3 extends XFrame {
|
||||
public void close() {
|
||||
setVisible(false);
|
||||
if (tsk != null) {
|
||||
tsk.cancel();
|
||||
tsk.cancel(false);
|
||||
}
|
||||
if (st != null) {
|
||||
st.remove(ti);
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jfree.chart.plot.dial.DialTextAnnotation;
|
||||
import org.jfree.data.general.DefaultValueDataset;
|
||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||
import org.kne.cloud.network.klalb.CONST;
|
||||
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||
import org.kne.cloud.network.perf.Kperf;
|
||||
@@ -35,17 +36,17 @@ import java.awt.event.ActionEvent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Font;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
public class KperfGUI extends XFrame{
|
||||
private static Timer tmr=new Timer();
|
||||
|
||||
private KperfReports reports=new KperfReportsImpl();
|
||||
private Kperf kperf;
|
||||
private JTextField targetAddressField;
|
||||
private JButton startButton;
|
||||
private JProgressBar progressBar;
|
||||
private DefaultValueDataset upSpeed;
|
||||
private DefaultValueDataset upDataSpeed;
|
||||
private DialTextAnnotation upSpeedText;
|
||||
@@ -54,7 +55,7 @@ public class KperfGUI extends XFrame{
|
||||
private DialTextAnnotation downSpeedText;
|
||||
private JTextField sourceAddressField;
|
||||
|
||||
private SpeedAndTrafficAndDelayMonitorDataImpl monitor;
|
||||
private volatile SpeedAndTrafficAndDelayMonitorDataImpl monitor;
|
||||
|
||||
private DefaultValueDataset upPPS;
|
||||
|
||||
@@ -68,12 +69,8 @@ public class KperfGUI extends XFrame{
|
||||
|
||||
private DialTextAnnotation downPPSText;
|
||||
|
||||
private TimerTask tsk;
|
||||
private ScheduledFuture<?> tsk;
|
||||
private class KperfReportsImpl implements KperfReports{
|
||||
@Override
|
||||
public void testProcess(double process) {
|
||||
progressBar.setValue((int) (process*100.0f));
|
||||
}
|
||||
@Override
|
||||
public void testFinish() {
|
||||
if(kperf!=null) {
|
||||
@@ -217,253 +214,11 @@ public class KperfGUI extends XFrame{
|
||||
|
||||
|
||||
|
||||
/*
|
||||
{
|
||||
upSpeed = new DefaultValueDataset(0);
|
||||
upDataSpeed = new DefaultValueDataset(0);
|
||||
DialPlot dpup = new DialPlot();
|
||||
dpup.setDataset(1, upSpeed);
|
||||
dpup.setDataset(0, upDataSpeed);
|
||||
StandardDialFrame sdfs = new StandardDialFrame();
|
||||
sdfs.setVisible(false);
|
||||
dpup.setDialFrame(sdfs);
|
||||
StandardDialScale sds = new StandardDialScale(0, 100, -120, -300, 10, 5);
|
||||
sds.setTickRadius(0.9);
|
||||
sds.setTickLabelsVisible(false);
|
||||
dpup.addScale(0, sds);
|
||||
|
||||
StandardDialRange sdrr = new StandardDialRange(0, 70, Color.GREEN);
|
||||
sdrr.setInnerRadius(0.92);
|
||||
sdrr.setOuterRadius(0.93);
|
||||
dpup.addLayer(sdrr);
|
||||
|
||||
StandardDialRange sdrr2 = new StandardDialRange(70, 90, Color.YELLOW);
|
||||
sdrr2.setInnerRadius(0.92);
|
||||
sdrr2.setOuterRadius(0.93);
|
||||
dpup.addLayer(sdrr2);
|
||||
|
||||
StandardDialRange sdrr3 = new StandardDialRange(90, 100, Color.RED);
|
||||
sdrr3.setInnerRadius(0.92);
|
||||
sdrr3.setOuterRadius(0.93);
|
||||
dpup.addLayer(sdrr3);
|
||||
|
||||
DialPointer.Pointer dpd = new DialPointer.Pointer();
|
||||
dpd.setRadius(0.8);
|
||||
dpd.setFillPaint(new Color(127, 0, 0, 0));
|
||||
dpd.setOutlinePaint(new Color(127, 0, 0));
|
||||
dpd.setDatasetIndex(0);
|
||||
//dpup.addLayer(dpd);
|
||||
|
||||
DialPointer.Pointer dp = new DialPointer.Pointer();
|
||||
dp.setRadius(0.8);
|
||||
dp.setFillPaint(Color.RED);
|
||||
dp.setOutlinePaint(Color.RED);
|
||||
dp.setDatasetIndex(1);
|
||||
dpup.addLayer(dp);
|
||||
|
||||
upSpeedText = new DialTextAnnotation("0%");
|
||||
upSpeedText.setFont(UIEnv.getFont().deriveFont(20.0f));
|
||||
dpup.addLayer(upSpeedText);
|
||||
|
||||
JFreeChart jfup = new JFreeChart(dpup);
|
||||
jfup.setBorderPaint(Color.WHITE);
|
||||
jfup.setTitle(UIEnv.getRsb().getString("uploadspeed"));
|
||||
jfup.getTitle().setFont(UIEnv.getFont().deriveFont(22.0f));
|
||||
jfup.getTitle().setPosition(RectangleEdge.BOTTOM);
|
||||
dpup.setView(0, 0, 1, 1);
|
||||
ChartPanel cpup = new ChartPanel(jfup);
|
||||
cpup.setPreferredSize(dashSize);
|
||||
cpup.setSize(dashSize);
|
||||
cpup.setMinimumSize(dashSize);
|
||||
cpup.setBackground(Color.WHITE);
|
||||
cpup.setBorder(new LineBorder(Color.LIGHT_GRAY));
|
||||
panel_3.add(cpup, BorderLayout.WEST);
|
||||
|
||||
downSpeed = new DefaultValueDataset(0);
|
||||
downDataSpeed = new DefaultValueDataset(0);
|
||||
DialPlot dpup1 = new DialPlot();
|
||||
dpup1.setDataset(1, downSpeed);
|
||||
dpup1.setDataset(0, downDataSpeed);
|
||||
StandardDialFrame sdfs1 = new StandardDialFrame();
|
||||
sdfs1.setVisible(false);
|
||||
dpup1.setDialFrame(sdfs1);
|
||||
StandardDialScale sds1 = new StandardDialScale(0, 100, -120, -300, 10, 5);
|
||||
sds1.setTickRadius(0.9);
|
||||
sds1.setTickLabelsVisible(false);
|
||||
dpup1.addScale(0, sds1);
|
||||
|
||||
StandardDialRange sdrr1 = new StandardDialRange(0, 70, Color.GREEN);
|
||||
sdrr1.setInnerRadius(0.92);
|
||||
sdrr1.setOuterRadius(0.93);
|
||||
dpup1.addLayer(sdrr1);
|
||||
|
||||
StandardDialRange sdrr21 = new StandardDialRange(70, 90, Color.YELLOW);
|
||||
sdrr21.setInnerRadius(0.92);
|
||||
sdrr21.setOuterRadius(0.93);
|
||||
dpup1.addLayer(sdrr21);
|
||||
|
||||
StandardDialRange sdrr31 = new StandardDialRange(90, 100, Color.RED);
|
||||
sdrr31.setInnerRadius(0.92);
|
||||
sdrr31.setOuterRadius(0.93);
|
||||
dpup1.addLayer(sdrr31);
|
||||
|
||||
DialPointer.Pointer dp11 = new DialPointer.Pointer();
|
||||
dp11.setRadius(0.8);
|
||||
dp11.setFillPaint(new Color(0, 127, 0, 0));
|
||||
dp11.setOutlinePaint(new Color(0, 127, 0));
|
||||
dp11.setDatasetIndex(0);
|
||||
//dpup1.addLayer(dp11);
|
||||
|
||||
DialPointer.Pointer dp1 = new DialPointer.Pointer();
|
||||
dp1.setRadius(0.8);
|
||||
dp1.setFillPaint(Color.GREEN);
|
||||
dp1.setOutlinePaint(Color.GREEN);
|
||||
dp1.setDatasetIndex(1);
|
||||
dpup1.addLayer(dp1);
|
||||
|
||||
downSpeedText = new DialTextAnnotation("0%");
|
||||
downSpeedText.setFont(UIEnv.getFont().deriveFont(20.0f));
|
||||
dpup1.addLayer(downSpeedText);
|
||||
|
||||
JFreeChart jfup1 = new JFreeChart(dpup1);
|
||||
jfup1.setBorderPaint(Color.WHITE);
|
||||
jfup1.setTitle(UIEnv.getRsb().getString("downloadspeed"));
|
||||
jfup1.getTitle().setFont(UIEnv.getFont().deriveFont(22.0f));
|
||||
jfup1.getTitle().setPosition(RectangleEdge.BOTTOM);
|
||||
dpup1.setView(0, 0, 1, 1);
|
||||
ChartPanel cpup1 = new ChartPanel(jfup1);
|
||||
cpup1.setPreferredSize(dashSize);
|
||||
cpup1.setSize(dashSize);
|
||||
cpup1.setMinimumSize(dashSize);
|
||||
cpup1.setBackground(Color.WHITE);
|
||||
cpup1.setBorder(new LineBorder(Color.LIGHT_GRAY));
|
||||
panel_4.add(cpup1, BorderLayout.WEST);
|
||||
|
||||
}
|
||||
{
|
||||
upPPS = new DefaultValueDataset(0);
|
||||
upDataPPS = new DefaultValueDataset(0);
|
||||
DialPlot dpup = new DialPlot();
|
||||
dpup.setDataset(1, upPPS);
|
||||
dpup.setDataset(0, upDataPPS);
|
||||
StandardDialFrame sdfs = new StandardDialFrame();
|
||||
sdfs.setVisible(false);
|
||||
dpup.setDialFrame(sdfs);
|
||||
StandardDialScale sds = new StandardDialScale(0, 100, -120, -300, 10, 5);
|
||||
sds.setTickRadius(0.9);
|
||||
sds.setTickLabelsVisible(false);
|
||||
dpup.addScale(0, sds);
|
||||
|
||||
StandardDialRange sdrr = new StandardDialRange(0, 70, Color.GREEN);
|
||||
sdrr.setInnerRadius(0.92);
|
||||
sdrr.setOuterRadius(0.93);
|
||||
dpup.addLayer(sdrr);
|
||||
|
||||
StandardDialRange sdrr2 = new StandardDialRange(70, 90, Color.YELLOW);
|
||||
sdrr2.setInnerRadius(0.92);
|
||||
sdrr2.setOuterRadius(0.93);
|
||||
dpup.addLayer(sdrr2);
|
||||
|
||||
StandardDialRange sdrr3 = new StandardDialRange(90, 100, Color.RED);
|
||||
sdrr3.setInnerRadius(0.92);
|
||||
sdrr3.setOuterRadius(0.93);
|
||||
dpup.addLayer(sdrr3);
|
||||
|
||||
DialPointer.Pointer dp1 = new DialPointer.Pointer();
|
||||
dp1.setRadius(0.8);
|
||||
dp1.setFillPaint(new Color(127, 0, 0, 0));
|
||||
dp1.setOutlinePaint(new Color(127, 0, 0));
|
||||
dp1.setDatasetIndex(0);
|
||||
//dpup.addLayer(dp1);
|
||||
|
||||
DialPointer.Pointer dp = new DialPointer.Pointer();
|
||||
dp.setRadius(0.8);
|
||||
dp.setFillPaint(Color.RED);
|
||||
dp.setOutlinePaint(Color.RED);
|
||||
dp.setDatasetIndex(1);
|
||||
dpup.addLayer(dp);
|
||||
|
||||
upPPSText = new DialTextAnnotation("0PPS");
|
||||
upPPSText.setFont(UIEnv.getFont().deriveFont(20.0f));
|
||||
dpup.addLayer(upPPSText);
|
||||
|
||||
JFreeChart jfup = new JFreeChart(dpup);
|
||||
jfup.setBorderPaint(Color.WHITE);
|
||||
jfup.setTitle(UIEnv.getRsb().getString("uploadpps"));
|
||||
jfup.getTitle().setFont(UIEnv.getFont().deriveFont(22.0f));
|
||||
jfup.getTitle().setPosition(RectangleEdge.BOTTOM);
|
||||
dpup.setView(0, 0, 1, 1);
|
||||
ChartPanel cpup = new ChartPanel(jfup);
|
||||
cpup.setPreferredSize(dashSize);
|
||||
cpup.setSize(cpup.getPreferredSize());
|
||||
cpup.setBackground(Color.WHITE);
|
||||
cpup.setBorder(new LineBorder(Color.LIGHT_GRAY));
|
||||
panel_5.add(cpup, BorderLayout.WEST);
|
||||
|
||||
downPPS = new DefaultValueDataset(0);
|
||||
downDataPPS = new DefaultValueDataset(0);
|
||||
DialPlot dpup1 = new DialPlot();
|
||||
dpup1.setDataset(1, downPPS);
|
||||
dpup1.setDataset(0, downDataPPS);
|
||||
StandardDialFrame sdfs1 = new StandardDialFrame();
|
||||
sdfs1.setVisible(false);
|
||||
dpup1.setDialFrame(sdfs1);
|
||||
StandardDialScale sds1 = new StandardDialScale(0, 100, -120, -300, 10, 5);
|
||||
sds1.setTickRadius(0.9);
|
||||
sds1.setTickLabelsVisible(false);
|
||||
dpup1.addScale(0, sds1);
|
||||
|
||||
StandardDialRange sdrr1 = new StandardDialRange(0, 70, Color.GREEN);
|
||||
sdrr1.setInnerRadius(0.92);
|
||||
sdrr1.setOuterRadius(0.93);
|
||||
dpup1.addLayer(sdrr1);
|
||||
|
||||
StandardDialRange sdrr21 = new StandardDialRange(70, 90, Color.YELLOW);
|
||||
sdrr21.setInnerRadius(0.92);
|
||||
sdrr21.setOuterRadius(0.93);
|
||||
dpup1.addLayer(sdrr21);
|
||||
|
||||
StandardDialRange sdrr31 = new StandardDialRange(90, 100, Color.RED);
|
||||
sdrr31.setInnerRadius(0.92);
|
||||
sdrr31.setOuterRadius(0.93);
|
||||
dpup1.addLayer(sdrr31);
|
||||
|
||||
DialPointer.Pointer dp111 = new DialPointer.Pointer();
|
||||
dp111.setRadius(0.8);
|
||||
dp111.setFillPaint(new Color(0, 127, 0, 0));
|
||||
dp111.setOutlinePaint(new Color(0, 127, 0));
|
||||
dp111.setDatasetIndex(0);
|
||||
///dpup1.addLayer(dp111);
|
||||
DialPointer.Pointer dp11 = new DialPointer.Pointer();
|
||||
dp11.setRadius(0.8);
|
||||
dp11.setFillPaint(Color.GREEN);
|
||||
dp11.setOutlinePaint(Color.GREEN);
|
||||
dp11.setDatasetIndex(1);
|
||||
dpup1.addLayer(dp11);
|
||||
|
||||
downPPSText = new DialTextAnnotation("0PPS");
|
||||
downPPSText.setFont(UIEnv.getFont().deriveFont(20.0f));
|
||||
dpup1.addLayer(downPPSText);
|
||||
|
||||
JFreeChart jfup1 = new JFreeChart(dpup1);
|
||||
jfup1.setBorderPaint(Color.WHITE);
|
||||
jfup1.setTitle(UIEnv.getRsb().getString("downloadpps"));
|
||||
jfup1.getTitle().setFont(UIEnv.getFont().deriveFont(22.0f));
|
||||
jfup1.getTitle().setPosition(RectangleEdge.BOTTOM);
|
||||
dpup1.setView(0, 0, 1, 1);
|
||||
ChartPanel cpup1 = new ChartPanel(jfup1);
|
||||
cpup1.setPreferredSize(dashSize);
|
||||
cpup1.setSize(cpup1.getPreferredSize());
|
||||
cpup1.setBackground(Color.WHITE);
|
||||
cpup1.setBorder(new LineBorder(Color.LIGHT_GRAY));
|
||||
panel_6.add(cpup1, BorderLayout.WEST);
|
||||
}*/
|
||||
|
||||
|
||||
// 上行速度仪表盘
|
||||
upSpeed = new DefaultValueDataset(0);
|
||||
upDataSpeed = new DefaultValueDataset(0);
|
||||
DialPanel dialup=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadspeed"), upSpeed, upDataSpeed, Color.RED, new Color(127, 0, 0));
|
||||
DialPanel dialup=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadspeed"), upSpeed, null, Color.RED, new Color(127, 0, 0));
|
||||
dialup.addGradientRanges(UIEnv.RANGE_1);
|
||||
upSpeedText =dialup.getTextAnnotation();
|
||||
|
||||
@@ -474,7 +229,7 @@ public class KperfGUI extends XFrame{
|
||||
// 下行速度仪表盘
|
||||
downSpeed = new DefaultValueDataset(0);
|
||||
downDataSpeed = new DefaultValueDataset(0);
|
||||
DialPanel dialdown=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadspeed"), downSpeed, downDataSpeed, Color.GREEN, new Color(0, 127, 0));
|
||||
DialPanel dialdown=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadspeed"), downSpeed, null, Color.GREEN, new Color(0, 127, 0));
|
||||
dialdown.addGradientRanges(UIEnv.RANGE_1);
|
||||
downSpeedText =dialdown.getTextAnnotation();
|
||||
|
||||
@@ -484,7 +239,7 @@ public class KperfGUI extends XFrame{
|
||||
// 上行包速率仪表盘
|
||||
upPPS = new DefaultValueDataset(0);
|
||||
upDataPPS = new DefaultValueDataset(0);
|
||||
DialPanel dialupPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadpps"), upPPS, upDataPPS, Color.RED, new Color(127, 0, 0));
|
||||
DialPanel dialupPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadpps"), upPPS, null, Color.RED, new Color(127, 0, 0));
|
||||
dialupPPS.addGradientRanges(UIEnv.RANGE_1);
|
||||
upPPSText = dialupPPS.getTextAnnotation();
|
||||
|
||||
@@ -493,7 +248,7 @@ public class KperfGUI extends XFrame{
|
||||
// 下行包速率仪表盘
|
||||
downPPS = new DefaultValueDataset(0);
|
||||
downDataPPS = new DefaultValueDataset(0);
|
||||
DialPanel dialdownPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadpps"), downPPS, downDataPPS, Color.GREEN, new Color(0, 127, 0));
|
||||
DialPanel dialdownPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadpps"), downPPS, null, Color.GREEN, new Color(0, 127, 0));
|
||||
dialdownPPS.addGradientRanges(UIEnv.RANGE_1);
|
||||
downPPSText = dialdownPPS.getTextAnnotation();
|
||||
|
||||
@@ -521,9 +276,6 @@ public class KperfGUI extends XFrame{
|
||||
|
||||
|
||||
|
||||
progressBar = new JProgressBar();
|
||||
progressBar.setPreferredSize(new Dimension(100, 5));
|
||||
getContentPane().add(progressBar, BorderLayout.NORTH);
|
||||
getTitlelabel().setFont(UIEnv.getFont().deriveFont(17.0f));
|
||||
getTitlepanel().setBorder(new LineBorder(Color.LIGHT_GRAY));
|
||||
getTitlelabel().setForeground(Color.WHITE);
|
||||
@@ -532,38 +284,37 @@ public class KperfGUI extends XFrame{
|
||||
setSize(CONST.windowwidth,CONST.windowheight );
|
||||
setResizable(false);
|
||||
setLocationRelativeTo(comp);
|
||||
tsk=new TimerTask() {
|
||||
tsk=KLALBScheduler.getScheduler().scheduleWithFixedDelay(new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if(monitor!=null) {
|
||||
double outload = monitor.getOutSpeed() * 100.0 / monitor.getOutSpeedMax();
|
||||
if (Double.isFinite(outload)) {
|
||||
upSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getOutSpeed()) + "/s");
|
||||
if (Double.isFinite(outload)) {
|
||||
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
||||
}
|
||||
|
||||
double inload = monitor.getInSpeed() * 100.0 / monitor.getInSpeedMax();
|
||||
if (Double.isFinite(inload)) {
|
||||
downSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getInSpeed()) + "/s");
|
||||
if (Double.isFinite(inload)) {
|
||||
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
||||
}
|
||||
|
||||
double outPPSload = monitor.getOutPPS() * 100.0 / monitor.getOutPPSMax();
|
||||
if (Double.isFinite(outPPSload)) {
|
||||
upPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getOutPPS()) + "PPS");
|
||||
if (Double.isFinite(outPPSload)) {
|
||||
upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
|
||||
}
|
||||
|
||||
double inPPSload = monitor.getInPPS() * 100.0 / monitor.getInPPSMax();
|
||||
if (Double.isFinite(inPPSload)) {
|
||||
downPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getInPPS()) + "PPS");
|
||||
if (Double.isFinite(inPPSload)) {
|
||||
downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
tmr.scheduleAtFixedRate(tsk, 200, 100);
|
||||
}, 200, 100, TimeUnit.MILLISECONDS);
|
||||
addWindowListener(new WindowListener() {
|
||||
|
||||
@Override
|
||||
@@ -593,7 +344,7 @@ public class KperfGUI extends XFrame{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
if(tsk!=null)
|
||||
tsk.cancel();
|
||||
tsk.cancel(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,8 +4,7 @@ import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.util.Date;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.Scanner;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
@@ -18,11 +17,15 @@ import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.data.time.Millisecond;
|
||||
import org.jfree.data.time.TimeSeries;
|
||||
import org.jfree.data.time.TimeSeriesCollection;
|
||||
import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.DetnetCongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||
import org.kne.cloud.network.congestion.Vegas2CongestionAlgorithm;
|
||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||
import org.kne.cloud.network.klalb.KLALBRemoteLink;
|
||||
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||
import org.kne.cloud.network.monitor.LinkStatus;
|
||||
import org.kne.cloud.network.monitor.TimestampMonitorValue;
|
||||
import org.kne.math.Long128;
|
||||
@@ -35,19 +38,18 @@ import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.swing.JSlider;
|
||||
|
||||
public class LineMonitorGUI extends XFrame {
|
||||
private Timer timer;
|
||||
private Timer timer1;
|
||||
private Timer timer2;
|
||||
private Timer timer3;
|
||||
private TimerTask tsk3;
|
||||
private ScheduledFuture<?> tsk3;
|
||||
|
||||
private TimerTask tsk4, tsk5,tsk6;
|
||||
private TimerTask d1;
|
||||
private TimerTask d2;
|
||||
private TimerTask d3;
|
||||
private ScheduledFuture<?> tsk4, tsk5,tsk6,tsk7;
|
||||
private ScheduledFuture<?> d1;
|
||||
private ScheduledFuture<?> d2;
|
||||
private ScheduledFuture<?> d3;
|
||||
private ScheduledFuture<?> d4;
|
||||
|
||||
private TimeSeries spdup = new TimeSeries(UIEnv.getRsb().getString("uploadspeed"));
|
||||
private TimeSeries spddown = new TimeSeries(UIEnv.getRsb().getString("downloadspeed"));
|
||||
@@ -62,13 +64,22 @@ public class LineMonitorGUI extends XFrame {
|
||||
private TimeSeries queueused = new TimeSeries(UIEnv.getRsb().getString("queueused"));
|
||||
private TimeSeries buffermax = new TimeSeries(UIEnv.getRsb().getString("maxbuffer"));
|
||||
|
||||
|
||||
private TimeSeries rttbaseline = new TimeSeries(UIEnv.getRsb().getString("rttbaseline"));
|
||||
private TimeSeries rtt = new TimeSeries(UIEnv.getRsb().getString("rtt"));
|
||||
private TimeSeries rttmin=new TimeSeries(UIEnv.getRsb().getString("rttmin"));
|
||||
private TimeSeries rttmax=new TimeSeries(UIEnv.getRsb().getString("rttmax"));
|
||||
private TimeSeries rto=new TimeSeries(UIEnv.getRsb().getString("rto"));
|
||||
|
||||
private KLALBRemoteLink tr;
|
||||
private JFreeChart jfc;
|
||||
private JFreeChart jfce;
|
||||
private JFreeChart jbfc;
|
||||
private JFreeChart jbfcv;
|
||||
private JLabel spdp;
|
||||
private JLabel delp;
|
||||
private JLabel sbpdp;
|
||||
private JLabel sbpdpv;
|
||||
private long timeRange = 5000;
|
||||
private long[] values = new long[] { 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000 };
|
||||
private JPanel panel_1;
|
||||
@@ -155,6 +166,24 @@ public class LineMonitorGUI extends XFrame {
|
||||
jp.add(sbpdp);
|
||||
|
||||
|
||||
TimeSeriesCollection tbsc1 = new TimeSeriesCollection();
|
||||
tbsc1.addSeries(rttbaseline);
|
||||
tbsc1.addSeries(rtt);
|
||||
tbsc1.addSeries(rttmax);
|
||||
tbsc1.addSeries(rttmin);
|
||||
tbsc1.addSeries(rto);
|
||||
jbfcv = ChartFactory.createTimeSeriesChart(UIEnv.getRsb().getString("congestionmonitor"),
|
||||
UIEnv.getRsb().getString("time") + "(s)", UIEnv.getRsb().getString("delay") + "(ms)", tbsc1);
|
||||
jbfcv.getXYPlot().setBackgroundPaint(Color.BLACK);
|
||||
jbfcv.getXYPlot().getRenderer().setSeriesPaint(0, Color.CYAN);
|
||||
jbfcv.getXYPlot().getRenderer().setSeriesPaint(1, Color.YELLOW);
|
||||
jbfcv.getXYPlot().getRenderer().setSeriesPaint(2, Color.RED);
|
||||
jbfcv.getXYPlot().getRenderer().setSeriesPaint(3, Color.GREEN);
|
||||
jbfcv.getXYPlot().getRenderer().setSeriesPaint(4, Color.ORANGE);
|
||||
changeFont(jbfcv);
|
||||
sbpdpv = new JLabel();
|
||||
sbpdpv.setBorder(new LineBorder(Color.DARK_GRAY));
|
||||
jp.add(sbpdpv);
|
||||
|
||||
|
||||
|
||||
@@ -262,6 +291,14 @@ public class LineMonitorGUI extends XFrame {
|
||||
buffermax.setMaximumItemCount((int) timeRange/5);
|
||||
queueused.setMaximumItemCount((int) timeRange/5);
|
||||
}
|
||||
synchronized (jbfcv) {
|
||||
|
||||
jbfcv.getXYPlot().getDomainAxis().setFixedAutoRange(timeRange);
|
||||
bufferused.setMaximumItemCount((int) timeRange/5);
|
||||
buffermax.setMaximumItemCount((int) timeRange/5);
|
||||
queueused.setMaximumItemCount((int) timeRange/5);
|
||||
}
|
||||
|
||||
windowSelect.setText(timeRange / 1000 + "s");
|
||||
}
|
||||
|
||||
@@ -328,44 +365,70 @@ public class LineMonitorGUI extends XFrame {
|
||||
}
|
||||
}
|
||||
}
|
||||
private void recordCongestionData() {
|
||||
if (isVisible()) {
|
||||
Millisecond ms = new Millisecond(
|
||||
new Date(tr.getMonitor().getClock().getCurrentTimeMillis()));
|
||||
synchronized (jbfcv) {
|
||||
CongestionAlgorithm window=tr.getWindow().getAlgorithm();
|
||||
if(window !=null) {
|
||||
double baseRTT = window.getBaseRTT();
|
||||
rttbaseline.addOrUpdate(ms, baseRTT / 1000000.0);
|
||||
rtt.addOrUpdate(ms, window.getCurrentRTT() / 1000000.0);
|
||||
rto.addOrUpdate(ms, window.getRTO() / 1000000.0);
|
||||
if (window instanceof DetnetCongestionAlgorithm) {
|
||||
|
||||
|
||||
Vegas2CongestionAlgorithm deta = (Vegas2CongestionAlgorithm) window;
|
||||
rttmax.addOrUpdate(ms, baseRTT * deta.getUpperDelayBound() / 1000000.0);
|
||||
rttmin.addOrUpdate(ms, baseRTT * deta.getLowerDelayBound() / 1000000.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void setVisible(boolean b) {
|
||||
if (b) {
|
||||
if (timer == null) {
|
||||
timer = new Timer();
|
||||
timer1 = new Timer();
|
||||
timer2 = new Timer();
|
||||
timer3 = new Timer();
|
||||
tsk3 = new TimerTask() {
|
||||
if (tsk3 == null) {
|
||||
|
||||
tsk3 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
updateTraffic();
|
||||
}
|
||||
};
|
||||
tsk4 = new TimerTask() {
|
||||
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||
tsk4 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
recordSpeedData();
|
||||
}
|
||||
};
|
||||
}, 10, 10, TimeUnit.MILLISECONDS);;
|
||||
|
||||
tsk5 = new TimerTask() {
|
||||
tsk5 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
recordDelayData();
|
||||
}
|
||||
};
|
||||
tsk6 = new TimerTask() {
|
||||
}, 10, 10, TimeUnit.MILLISECONDS);
|
||||
tsk6 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
recordBufferData();
|
||||
}
|
||||
};
|
||||
d1 = new TimerTask() {
|
||||
}, 10, 10, TimeUnit.MILLISECONDS);
|
||||
tsk7 = KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
recordCongestionData();
|
||||
}
|
||||
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||
d1 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -377,8 +440,8 @@ public class LineMonitorGUI extends XFrame {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
d2 = new TimerTask() {
|
||||
} ,25, 25, TimeUnit.MILLISECONDS);
|
||||
d2 = KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -391,8 +454,8 @@ public class LineMonitorGUI extends XFrame {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
d3 = new TimerTask() {
|
||||
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||
d3 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -405,40 +468,46 @@ public class LineMonitorGUI extends XFrame {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
timer.scheduleAtFixedRate(tsk3, 25, 25);
|
||||
timer1.scheduleAtFixedRate(tsk4, 10, 10);
|
||||
timer1.scheduleAtFixedRate(d1, 25, 25);
|
||||
timer2.scheduleAtFixedRate(tsk5, 10, 10);
|
||||
timer2.scheduleAtFixedRate(d2, 25, 25);
|
||||
timer3.scheduleAtFixedRate(tsk6, 10, 10);
|
||||
timer3.scheduleAtFixedRate(d3, 25, 25);
|
||||
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||
d4 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (isVisible()) {
|
||||
synchronized (jbfcv) {
|
||||
ImageIcon i3 = new ImageIcon(
|
||||
jbfcv.createBufferedImage(sbpdpv.getWidth(), sbpdpv.getHeight()));
|
||||
sbpdpv.setIcon(i3);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
if (tsk3 != null)
|
||||
tsk3.cancel();
|
||||
tsk3.cancel(false);
|
||||
if (tsk4 != null)
|
||||
tsk4.cancel();
|
||||
tsk4.cancel(false);
|
||||
if (tsk5 != null)
|
||||
tsk5.cancel();
|
||||
tsk5.cancel(false);
|
||||
if (tsk6 != null)
|
||||
tsk6.cancel(false);
|
||||
if (tsk7 != null)
|
||||
tsk7.cancel(false);
|
||||
if (d1 != null)
|
||||
d1.cancel();
|
||||
d1.cancel(false);
|
||||
if (d2 != null)
|
||||
d2.cancel();
|
||||
d2.cancel(false);
|
||||
if (d3 != null)
|
||||
d3.cancel();
|
||||
if (timer != null)
|
||||
timer.cancel();
|
||||
if (timer1 != null)
|
||||
timer1.cancel();
|
||||
|
||||
if (timer2 != null)
|
||||
timer2.cancel();
|
||||
|
||||
if (timer3 != null)
|
||||
timer3.cancel();
|
||||
timer = null;
|
||||
d3.cancel(false);
|
||||
if (d4 != null)
|
||||
d4.cancel(false);
|
||||
tsk3=null;
|
||||
}
|
||||
super.setVisible(b);
|
||||
}
|
||||
|
||||
@@ -3,20 +3,18 @@ package org.kne.cloud.network.kltp;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.BindException;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||
import org.kne.concurrent.*;
|
||||
import org.kne.cloud.network.NetworkPacket;
|
||||
import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.DCTCP2CongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.DCTCPCongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||
import org.kne.cloud.network.klalb.DATATPacket;
|
||||
import org.kne.cloud.network.klalb.KLALBController;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -238,23 +236,27 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if(sendMap.isClosed())
|
||||
if(sendMap.isClosed()) {
|
||||
tt.cancel(false);
|
||||
}else if(!sendMap.isCongestion()){
|
||||
try {
|
||||
if(olock!=null)
|
||||
if (olock != null)
|
||||
olock.lock();
|
||||
try {
|
||||
if(!sendMap.isCongestion()) {
|
||||
flush0();
|
||||
}finally {
|
||||
if(olock!=null)
|
||||
}
|
||||
} finally {
|
||||
if (olock != null)
|
||||
olock.unlock();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ioe.set(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
tt=controller.getScheduleTimer().scheduleAtFixedRate (r, delaytime, delaytime,TimeUnit.NANOSECONDS);
|
||||
tt= KLALBScheduler.getScheduler().scheduleWithFixedDelay(r, delaytime, delaytime,TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
IOException ioex=ioe.get();
|
||||
@@ -271,7 +273,7 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
||||
|
||||
sendMap.waitForAvaliable();
|
||||
|
||||
controller.getIpv6Router().runPacketSendTask(()->{
|
||||
controller.getIpv6Router().enqueuePacketSendTask(()->{
|
||||
pack.getKLTPData().flip();
|
||||
pack.incSendCounter();
|
||||
sendMap.put(pack.getSequence(),pack);
|
||||
@@ -353,7 +355,7 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
||||
KLTPPacket kltp=(KLTPPacket) u.getPayload();
|
||||
switch(kltp.getType()) {
|
||||
case KLTPPacket.KLTP_TYPE_ACK:
|
||||
sendMap.ack(kltp.getSequence(), kltp.isCE());
|
||||
sendMap.ack(kltp.getSequence(),0, kltp.isCE());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
||||
return clock;
|
||||
}
|
||||
|
||||
protected ArrayListTimestampMonitor(HighAccuracyClock clock, String name, int maxRetry, long cleanupThreshold) {
|
||||
public ArrayListTimestampMonitor(HighAccuracyClock clock, String name, int maxRetry, long cleanupThreshold) {
|
||||
super();
|
||||
this.clock = clock;
|
||||
this.name = name;
|
||||
@@ -67,6 +67,11 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
||||
return recordPacket(key,clock.getCurrentTimeNanos(),count,length);
|
||||
}
|
||||
|
||||
|
||||
public boolean recordPacket(K key, int count, int length, long delay, long delayMin) {
|
||||
return recordPacket(key, clock.getCurrentTimeNanos(),count, length, delay,delayMin);
|
||||
}
|
||||
|
||||
public boolean recordPacket(K key,int count, int length, long delay) {
|
||||
return recordPacket(key, clock.getCurrentTimeNanos(),count, length, delay);
|
||||
}
|
||||
@@ -75,17 +80,22 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
||||
return recordPacket(key, timestamp,count, length, Long.MAX_VALUE / 1024);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean recordPacket(K key, Long128 timestamp, int count, int length, long dsndDelay) {
|
||||
return recordPacket(key, timestamp, count, length, dsndDelay,dsndDelay);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 记录数据包 - 使用插入排序保持列表有序,添加时间戳验证
|
||||
*/
|
||||
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay) {
|
||||
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay, long dsndDelayMin) {
|
||||
// 验证时间戳的合理性
|
||||
validateTimestamp(timestamp);
|
||||
|
||||
// 快速路径:尝试sequence=0
|
||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey, timestamp,count, length, delay);
|
||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey, timestamp,count, length, delay,dsndDelayMin);
|
||||
autoCleanup(cleanupThreshold);
|
||||
|
||||
rwLock.writeLock().lock();
|
||||
@@ -461,6 +471,48 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 从已排序的列表中计算数据量 - 优化版本,只需要startTime
|
||||
*/
|
||||
private long calculateMinDelayFromSortedList(List<TimestampMonitorValue> sortedList, Long128 startTime) {
|
||||
if (sortedList.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 使用二分查找找到第一个 >= startTime 的元素位置
|
||||
int startIndex = findFirstValidIndexFromSorted(sortedList, startTime);
|
||||
|
||||
if (startIndex >= sortedList.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 计算从startIndex到末尾的所有数据量(因为数据包不会来自未来)
|
||||
long sum = Long.MAX_VALUE/1024;
|
||||
for (int i = startIndex; i < sortedList.size(); i++) {
|
||||
sum =Math.min(sortedList.get(i).getDelayMin(),sum) ;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long calculateMinDelay(long timeWindowNs){
|
||||
return calculateMinDelay(clock.getCurrentTimeNanos(),timeWindowNs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long calculateMinDelay(Long128 currentTime, long timeWindowNs){
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return calculateMinDelayFromSortedList(entries, startTime);
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private volatile TimestampMonitorValue recent=null;
|
||||
@Override
|
||||
public TimestampMonitorValue getRecentDelayEntry() {
|
||||
|
||||
@@ -76,15 +76,22 @@ private String name;
|
||||
return recordPacket(key,clock.getCurrentTimeNanos(),count,length,delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean recordPacket(K key, int count, int length, long delay, long delayMin) {
|
||||
return recordPacket(key,clock.getCurrentTimeNanos(),count,length,delay,delayMin);
|
||||
}
|
||||
|
||||
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay) {
|
||||
return recordPacket(key,timestamp,count,length,delay,delay);
|
||||
}
|
||||
/**
|
||||
* 超高性能记录数据包 - 针对路由器优化
|
||||
*/
|
||||
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay) {
|
||||
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay,long delayMin) {
|
||||
autoCleanup(cleanupThreshold);
|
||||
// 快速路径:尝试sequence=0
|
||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey,timestamp, count,length,delay);
|
||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey,timestamp, count,length,delay,delayMin);
|
||||
|
||||
if (entries.putIfAbsent(monitorKey, monitorValue) == null) {
|
||||
totalDataSize.add(length);
|
||||
@@ -304,6 +311,17 @@ private String name;
|
||||
// TODO 自动生成的方法存根
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long calculateMinDelay(long timeWindowNs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long calculateMinDelay(Long128 currentTime, long timeWindowNs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimestampMonitorValue getRecentDelayEntry() {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
@@ -19,27 +19,17 @@ public class SpeedAndTrafficAndDelayMonitorDataImpl extends SpeedAndTrafficMonit
|
||||
upSampler.update();
|
||||
downSampler.update();
|
||||
if(upSampler.getSnapshotPacketCount()>0&&upSampler.getSnapshotTotalDelay()>0) {
|
||||
getUploadBandwidth(). recordPacket(KLALBUtils.createGlobalUUID(),0, 0, upSampler.getAvgDelayNanos());
|
||||
getUploadBandwidth(). recordPacket(KLALBUtils.createGlobalUUID(),0, 0, upSampler.getAvgDelayNanos(),upSampler.getMinDelayNanos());
|
||||
}
|
||||
if(downSampler.getSnapshotPacketCount()>0&&downSampler.getSnapshotTotalDelay()>0) {
|
||||
getDownloadBandwidth(). recordPacket(KLALBUtils.createGlobalUUID(),0, 0, downSampler.getAvgDelayNanos());
|
||||
getDownloadBandwidth(). recordPacket(KLALBUtils.createGlobalUUID(),0, 0, downSampler.getAvgDelayNanos(),downSampler.getMinDelayNanos());
|
||||
}
|
||||
|
||||
long time=System.nanoTime();
|
||||
if(time-stime>timewindowmax) {
|
||||
outDelayMin=getUploadBandwidth().calculateMinDelay(super.getTimeWindowMax());
|
||||
inDelayMin=getDownloadBandwidth().calculateMinDelay(super.getTimeWindowMax());
|
||||
stime=time;
|
||||
long idelay=getInDelay();
|
||||
if(inDelayMin==Long.MAX_VALUE||idelay<=inDelayMin) {
|
||||
inDelayMin=idelay;
|
||||
}else{
|
||||
inDelayMin=(inDelayMin*99+idelay)/100;
|
||||
}
|
||||
long odelay=getOutDelay();
|
||||
if(outDelayMin==Long.MAX_VALUE||odelay<=outDelayMin) {
|
||||
outDelayMin=odelay;
|
||||
}else{
|
||||
outDelayMin=(outDelayMin*99+odelay)/100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@ public class SpeedAndTrafficMonitorDataImpl extends MonitorDataImpl implements S
|
||||
private TimestampMonitor<UUID>uploadBandwidth;
|
||||
private TimestampMonitor<UUID>downloadBandwidth;
|
||||
private long timewindow=1000000000L;
|
||||
private long timewindowmax=1000000000L;
|
||||
private long timewindowmax=30000000000L;
|
||||
private BandwidthSampler upSampler=new BandwidthSampler();
|
||||
private BandwidthSampler downSampler=new BandwidthSampler();
|
||||
|
||||
|
||||
|
||||
private final long TIME_WINDOW=2000000000L;
|
||||
private final long TIME_WINDOW=50000000000L;
|
||||
public SpeedAndTrafficMonitorDataImpl(HighAccuracyClock clock) {
|
||||
super();
|
||||
this.clock=clock;
|
||||
@@ -177,32 +177,39 @@ public class SpeedAndTrafficMonitorDataImpl extends MonitorDataImpl implements S
|
||||
inPPSEvaluator.markDirty();
|
||||
}
|
||||
long time=System.nanoTime();
|
||||
if(time-stime>timewindowmax) {
|
||||
if(time-stime>timewindow) {
|
||||
stime=time;
|
||||
long os=uploadBandwidth.calculateBandwidth(timewindowmax);
|
||||
long is=downloadBandwidth.calculateBandwidth(timewindowmax);
|
||||
long op=uploadBandwidth.calculatePacketRate(timewindowmax);
|
||||
long ip=uploadBandwidth.calculatePacketRate(timewindowmax);
|
||||
if(os>outSpeeedMax) {
|
||||
outSpeeedMax=(outSpeeedMax+os)/2;
|
||||
outSpeeedMax=os;
|
||||
}else {
|
||||
outSpeeedMax=(outSpeeedMax*999+os)/1000;
|
||||
}
|
||||
if(is>inSpeedMax) {
|
||||
inSpeedMax=(inSpeedMax+is)/2;
|
||||
inSpeedMax=is;
|
||||
}else {
|
||||
inSpeedMax=(inSpeedMax*999+is)/1000;
|
||||
}
|
||||
if(op>outPPSMax) {
|
||||
outPPSMax=(outPPSMax+op)/2;
|
||||
outPPSMax=op;
|
||||
}else {
|
||||
outPPSMax=(outPPSMax*999+op)/1000;
|
||||
}
|
||||
if(ip>inPPSMax) {
|
||||
inPPSMax=(inPPSMax+ip)/2;
|
||||
inPPSMax=ip;
|
||||
}else {
|
||||
inPPSMax=(inPPSMax*999+ip)/1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected long getTimeWindow() {
|
||||
return timewindow;
|
||||
}
|
||||
protected long getTimeWindowMax() {
|
||||
return timewindowmax;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.kne.cloud.network.monitor;
|
||||
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.network.ipv6.PacketID;
|
||||
import org.kne.math.Long128;
|
||||
|
||||
/**
|
||||
@@ -37,6 +36,9 @@ public interface TimestampMonitor<K> {
|
||||
*/
|
||||
boolean recordPacket(K key,int count, int length);
|
||||
|
||||
boolean recordPacket(K key, int count,int length, long dsndDelay);
|
||||
|
||||
boolean recordPacket(K key, int count, int length, long avgDelayNanos, long minDelayNanos);
|
||||
/**
|
||||
* 记录数据包(使用指定时间戳)
|
||||
* @param key 数据包标识
|
||||
@@ -49,7 +51,9 @@ public interface TimestampMonitor<K> {
|
||||
|
||||
boolean recordPacket(K key, Long128 timestamp, int count,int length, long dsndDelay);
|
||||
|
||||
boolean recordPacket(K key, int count,int length, long dsndDelay);
|
||||
|
||||
|
||||
boolean recordPacket(K key, Long128 timestamp, int count,int length, long dsndDelay,long dsndDelayMin);
|
||||
|
||||
// ==================== 清理维护方法 ====================
|
||||
|
||||
@@ -146,6 +150,10 @@ public interface TimestampMonitor<K> {
|
||||
long getRecentDelay();
|
||||
|
||||
|
||||
long calculateMinDelay(long timeWindowNs);
|
||||
|
||||
long calculateMinDelay(Long128 currentTime, long timeWindowNs);
|
||||
|
||||
TimestampMonitorValue getRecentDelayEntry();
|
||||
|
||||
|
||||
|
||||
@@ -8,22 +8,26 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
||||
private final int length;
|
||||
private final TimestampMonitorKey<?> key;
|
||||
private long delay;
|
||||
private long delayMin;
|
||||
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp,int count, int length) {
|
||||
this(key,timestamp,count,length,Long.MAX_VALUE/1024);
|
||||
this(key,timestamp,count,length,Long.MAX_VALUE/1024,Long.MAX_VALUE/1024);
|
||||
}
|
||||
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp,int count, int length,long delay) {
|
||||
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp,int count, int length,long delay,long delayMin) {
|
||||
this.key = key;
|
||||
this.timestamp = timestamp;
|
||||
this.count=count;
|
||||
this.length = length;
|
||||
this.delay=delay;
|
||||
this.delayMin=delayMin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + count;
|
||||
result = prime * result + (int) (delay ^ (delay >>> 32));
|
||||
result = prime * result + (int) (delayMin ^ (delayMin >>> 32));
|
||||
result = prime * result + length;
|
||||
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
|
||||
return result;
|
||||
@@ -38,8 +42,12 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
TimestampMonitorValue other = (TimestampMonitorValue) obj;
|
||||
if (count != other.count)
|
||||
return false;
|
||||
if (delay != other.delay)
|
||||
return false;
|
||||
if (delayMin != other.delayMin)
|
||||
return false;
|
||||
if (length != other.length)
|
||||
return false;
|
||||
if (timestamp == null) {
|
||||
@@ -52,8 +60,8 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimestampMonitorValue [timestamp=" + timestamp + ", length=" + length + ", key=" + key + ", delay="
|
||||
+ delay + "]";
|
||||
return "TimestampMonitorValue [timestamp=" + timestamp + ", count=" + count + ", length=" + length
|
||||
+ ", delay=" + delay + ", delayMin=" + delayMin + "]";
|
||||
}
|
||||
|
||||
public Long128 getTimestamp() { return timestamp; }
|
||||
@@ -73,6 +81,12 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
public long getDelayMin() {
|
||||
return delayMin;
|
||||
}
|
||||
public void setDelayMin(long delayMin) {
|
||||
this.delayMin = delayMin;
|
||||
}
|
||||
@Override
|
||||
public int compareTo(TimestampMonitorValue other) {
|
||||
return this.timestamp.compareTo(other.timestamp);
|
||||
|
||||
@@ -117,7 +117,7 @@ public class NTPContext implements Closeable, AutoCloseable {
|
||||
}
|
||||
|
||||
protected void putPacket(NTPv4Packet nv4, MultiProtocolSocketAddress inetSocketAddress) {
|
||||
checkIP();
|
||||
//checkIP();
|
||||
List<NTPv4Packet> newv = new Vector<NTPv4Packet>();
|
||||
List<NTPv4Packet> oldv = recvmap.putIfAbsent(inetSocketAddress, newv);
|
||||
if (oldv == null) {
|
||||
@@ -132,25 +132,6 @@ public class NTPContext implements Closeable, AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIP() {
|
||||
Set<Entry<MultiProtocolSocketAddress, List<NTPv4Packet>>> ens = recvmap.entrySet();
|
||||
for (Iterator<Entry<MultiProtocolSocketAddress, List<NTPv4Packet>>> iterator = ens.iterator(); iterator
|
||||
.hasNext();) {
|
||||
Entry<MultiProtocolSocketAddress, List<NTPv4Packet>> entry = (Entry<MultiProtocolSocketAddress, List<NTPv4Packet>>) iterator
|
||||
.next();
|
||||
AtomicBoolean ab = new AtomicBoolean(false);
|
||||
ios.forEach((x) -> {
|
||||
if (!ab.get())
|
||||
if (x.findPeer(entry.getKey()) != null) {
|
||||
ab.set(true);
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (!ab.get()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PeerInfo implements Comparable<PeerInfo> {
|
||||
private MultiProtocolSocketAddress address;
|
||||
@@ -225,14 +206,12 @@ public class NTPContext implements Closeable, AutoCloseable {
|
||||
PeerInfo pix = peerInfo.get(0);
|
||||
currentClock = pix;
|
||||
int i;
|
||||
int m = Math.min(peerInfo.size(), 3);
|
||||
Long128 bi = Long128.ZERO;
|
||||
for (i = 0; i < m; i++) {
|
||||
PeerInfo pi = peerInfo.get(i);
|
||||
Long128 adjt = pi.getAdj();
|
||||
bi = bi.add(adjt);
|
||||
List<Long128> adjts = new ArrayList<>();
|
||||
for (i = 0; i < peerInfo.size(); i++) {
|
||||
adjts.add(peerInfo.get(i).getAdj());
|
||||
}
|
||||
Long128 delta = bi.divide(Long128.valueOf(i));
|
||||
Long128 delta = NTPTimestamps. median(adjts);
|
||||
//System.out.println(adjts+":"+delta);
|
||||
avgAdj=(avgAdj*7+delta.abs().longValue())/8;
|
||||
Long128 deltaabs=delta.abs();
|
||||
if (deltaabs.compareTo(adjustThreshold0) > 0&&firstSync.compareAndSet(true, false)) {
|
||||
|
||||
@@ -252,14 +252,23 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
||||
checkLock.unlock();
|
||||
}
|
||||
}
|
||||
// 在类成员变量中定义 ThreadLocal 发送缓冲区
|
||||
private static final ThreadLocal<ByteBuffer> NTP_TX_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(9000));
|
||||
|
||||
private void sendNTPPacket(NTPv4Packet nv4, SocketAddress target) throws IOException {
|
||||
ByteBuffer bbf = ByteBuffer.allocate(65535);
|
||||
// 1. 获取并重置缓冲区
|
||||
ByteBuffer bbf = NTP_TX_BUFFER.get();
|
||||
bbf.clear(); // 重置 position=0, limit=9000
|
||||
|
||||
// 2. 写入数据
|
||||
nv4.writeToChannel(KNEChannels.newWritableChannel(bbf));
|
||||
bbf.flip();
|
||||
bbf.flip(); // 切换为读模式,limit 会变成实际写入的长度
|
||||
|
||||
// 3. 发送
|
||||
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||
dp.setSocketAddress(target);
|
||||
dgs.send(dp);
|
||||
|
||||
if (showPacket)
|
||||
System.out.println("NTPv4 TX:" + target + " " + nv4);
|
||||
}
|
||||
@@ -379,15 +388,30 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
||||
return sends;
|
||||
}
|
||||
|
||||
// 1. 在类成员变量中定义 ThreadLocal 缓冲区
|
||||
private static final ThreadLocal<ByteBuffer> NTP_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(9000));
|
||||
|
||||
private NTPv4Packet receiveNTPPacket(AtomicReference<InetSocketAddress> isa) throws IOException {
|
||||
ByteBuffer bbf = ByteBuffer.allocate(65535);
|
||||
// 2. 从 ThreadLocal 获取,并重置状态 (position=0, limit=9000)
|
||||
ByteBuffer bbf = NTP_BUFFER.get();
|
||||
bbf.clear();
|
||||
|
||||
// 3. 构造 DatagramPacket
|
||||
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||
dgs.receive(dp);
|
||||
|
||||
isa.set((InetSocketAddress) dp.getSocketAddress());
|
||||
|
||||
// 4. 关键:限制 ByteBuffer 的读取范围,防止越界读取历史脏数据
|
||||
bbf.limit(dp.getLength());
|
||||
|
||||
NTPv4Packet nv4 = new NTPv4Packet(context.getClock());
|
||||
// 5. 将 Channel 的读取操作限制在 dp.getLength() 长度内
|
||||
nv4.readFromChannel(KNEChannels.newReadableChannel(bbf), dp.getLength());
|
||||
|
||||
if (showPacket)
|
||||
System.out.println("NTPv4 RX:" + isa.get() + " " + nv4);
|
||||
|
||||
return nv4;
|
||||
}
|
||||
|
||||
@@ -405,18 +429,5 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
||||
return dgs.isClosed();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
HighAccuracyClock hac = new HighAccuracyClock();
|
||||
NTPContext context = new NTPContext(hac);
|
||||
System.out.println(context);
|
||||
NTPv4Protocol nvc = new NTPv4Protocol(context, new MultiProtocolSocketAddress("{UDP}0.0.0.0:123"));// 106.55.184.199
|
||||
nvc.getPeers().add(new NTPPeer("{UDP}106.55.184.199:123", NTPv4Packet.NTP_CLIENT));
|
||||
nvc.getPeers().add(new NTPPeer("{UDP}time.windows.com:123", NTPv4Packet.NTP_CLIENT));
|
||||
nvc.getPeers().add(new NTPPeer("{UDP}127.0.0.1:123", NTPv4Packet.NTP_SYMMETRIC_ACTIVE));
|
||||
/*
|
||||
* for (int i = 0; i < 10000; i++) { Thread.sleep(1000);
|
||||
* System.out.println(context.getCurrentSelfDispersion128());
|
||||
* System.out.println(context); }
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,20 +4,20 @@ import java.io.IOException;
|
||||
import java.nio.channels.UnresolvedAddressException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.kne.cloud.clock.AdjustedNanoClock;
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.clock.NTPTimestamps;
|
||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||
import org.kne.cloud.network.SpeedLimiter;
|
||||
import org.kne.cloud.network.ThreadTool;
|
||||
import org.kne.cloud.network.klalb.KLALBPacket;
|
||||
import org.kne.cloud.network.klalb.KLALBPacketLink;
|
||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||
import org.kne.cloud.network.klalb.PINGPacket;
|
||||
import org.kne.cloud.network.klalb.PONGPacket;
|
||||
import org.kne.cloud.network.klalb.*;
|
||||
import org.kne.cloud.network.monitor.LinkStatus;
|
||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||
import org.kne.concurrent.ThreadParker;
|
||||
import org.kne.math.Long128;
|
||||
|
||||
public class Kperf implements Runnable{
|
||||
|
||||
@@ -38,8 +38,8 @@ public class Kperf implements Runnable{
|
||||
private volatile KLALBPacketLink link;
|
||||
|
||||
private LinkStatus status=new LinkStatus();
|
||||
private SpeedAndTrafficAndDelayMonitorDataImpl monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(HighAccuracyClock.SYSTEM_CLOCK);
|
||||
|
||||
private HighAccuracyClock sysclk =HighAccuracyClock.SYSTEM_CLOCK;
|
||||
private SpeedAndTrafficAndDelayMonitorDataImpl monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
||||
private volatile boolean closed = false;
|
||||
|
||||
private volatile ThreadParker tlock=new ThreadParker();
|
||||
@@ -79,25 +79,20 @@ public class Kperf implements Runnable{
|
||||
|
||||
|
||||
|
||||
KLALBPacket testPacket=null;
|
||||
private KLALBPacket testPacket=null;
|
||||
|
||||
private long starttime=System.nanoTime();
|
||||
long totaltime=1000;
|
||||
long usedtime=0;
|
||||
|
||||
|
||||
private MonitorUpdater monitorUpdater;
|
||||
private ScheduledFuture<?> monitorUpdater;
|
||||
private class MonitorUpdater implements Runnable{
|
||||
@Override
|
||||
public void run() {
|
||||
while (!closed) {
|
||||
if (closed) {
|
||||
monitorUpdater.cancel(false);
|
||||
}else{
|
||||
status.updateReliability();
|
||||
monitor.update();
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -126,9 +121,9 @@ public class Kperf implements Runnable{
|
||||
});
|
||||
Thread tc = ThreadTool.makeVDaemonThreadIfSupport("测速控制线程", () -> {
|
||||
final int wtimes=5;
|
||||
totaltime=(20*1000*1+20*1000*4+wtimes*1000*5)*1000000L;
|
||||
starttime=System.nanoTime();
|
||||
System.out.println("测速开始!");
|
||||
if(reports!=null)
|
||||
reports.updateDial(monitor);
|
||||
try {
|
||||
long startTime;
|
||||
|
||||
@@ -137,7 +132,6 @@ public class Kperf implements Runnable{
|
||||
startTime=System.nanoTime();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Thread.sleep(1000);
|
||||
updateUsedTime();
|
||||
}
|
||||
System.out.printf("上传延迟 最小:%.3fms 平均:%.3fms 抖动:%.3fms\n",monitor.getOutDelay()/1000000.0,monitor.getOutDelay()/1000000.0,monitor.getOutJitter()/1000000.0);
|
||||
System.out.printf("下载延迟 最小:%.3fms 平均:%.3fms 抖动:%.3fms\n",monitor.getInDelay()/1000000.0,monitor.getInDelay()/1000000.0,monitor.getInJitter()/1000000.0);
|
||||
@@ -153,7 +147,7 @@ public class Kperf implements Runnable{
|
||||
|
||||
System.out.println("测试2/3:带宽测试");
|
||||
test.setLimitspeed(1000L*1024L*1024L*1024L);
|
||||
testPacket=new TESTNPacket(65535);
|
||||
testPacket=new TESTNPacket(9000);
|
||||
for (int i = 0; i < 60; i++) {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
@@ -208,7 +202,9 @@ public class Kperf implements Runnable{
|
||||
|
||||
while ((!link.isClosed()) && (!closed)) {
|
||||
if (checkPingTimeSleep()) {
|
||||
writePacketToKPL(new PINGPacket(System.nanoTime(),0, 0));
|
||||
PINGPacket ping = new PINGPacket(sysclk.getCurrentTimeNTP64().longValue(), monitor.getOutSpeed(),
|
||||
monitor.getInSpeed());
|
||||
writePacketToKPL(ping);
|
||||
|
||||
}else {
|
||||
KLALBPacket kpip = IsendDequeList.poll();
|
||||
@@ -251,7 +247,17 @@ public class Kperf implements Runnable{
|
||||
}
|
||||
switch (kpp.getType()) {
|
||||
case KLALBPacket.PING:
|
||||
sendIPacket(new PONGPacket(((PINGPacket) kpp).getTime() ,kpp.getRcvtime(), System.nanoTime(),0, 0));
|
||||
long pct = System.nanoTime() - kpp.getRcvtime();
|
||||
Long128 curr = sysclk.getCurrentTimeNanos();
|
||||
Long128 rcv = curr.subtract(pct);
|
||||
|
||||
Long128 local1281 = NTPTimestamps.nanosToNtp128BitTimestamp(curr);
|
||||
PONGPacket pong = new PONGPacket(((PINGPacket) kpp).getTime(),
|
||||
NTPTimestamps.ntp128To64(NTPTimestamps.nanosToNtp128BitTimestamp(rcv)).longValue(),
|
||||
NTPTimestamps.ntp128To64(NTPTimestamps.nanosToNtp128BitTimestamp(curr)).longValue(),
|
||||
monitor.getUploadBandwidth().calculateBandwidth(500000000L),
|
||||
monitor.getDownloadBandwidth().calculateBandwidth(500000000L));
|
||||
sendIPacket(pong);
|
||||
break;
|
||||
case KLALBPacket.PONG:
|
||||
if (fst) {
|
||||
@@ -270,42 +276,45 @@ public class Kperf implements Runnable{
|
||||
}
|
||||
|
||||
PONGPacket png = (PONGPacket) kpp;
|
||||
long ul = png.getRcvtime() - png.getTimepingsnd()-(png.getTimepongsnd()-png.getTimepingrcv());
|
||||
Long128 local = sysclk.getCurrentTimeNanos();
|
||||
Long128 local128 = NTPTimestamps.nanosToNtp128BitTimestamp(local);
|
||||
|
||||
long DsndDelayFactor0 = png.getTimepingrcv() - png.getTimepingsnd();
|
||||
long DrcvDelayFactor0 = png.getRcvtime() - png.getTimepongsnd();
|
||||
long DsndDelayFactor;
|
||||
long DrcvDelayFactor;
|
||||
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||
NTPTimestamps.inferNtp64To128(png.getTimepingsnd(), local128));
|
||||
// System.out.println("psnd"+NTPTimestamps.nanosSince1970ToString(
|
||||
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
// psnd,local128))));
|
||||
Long128 prcv = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||
NTPTimestamps.inferNtp64To128(png.getTimepingrcv(), local128));
|
||||
// System.out.println("prcv"+NTPTimestamps.nanosSince1970ToString(
|
||||
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
// prcv,local128))));
|
||||
Long128 posnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||
NTPTimestamps.inferNtp64To128(png.getTimepongsnd(), local128));
|
||||
// System.out.println("posnd"+NTPTimestamps.nanosSince1970ToString(
|
||||
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
// posnd,local128))));
|
||||
|
||||
adjnc.getLock().lock();
|
||||
try {
|
||||
adjnc.calibrate(png.getTimepongsnd() + ul / 2 - png.getRcvtime(), ul / 2);
|
||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
||||
if (DsndDelayFactor < 0) {
|
||||
if (DrcvDelayFactor < 0) {
|
||||
long DsndDelay = prcv.subtract(psnd).longValue();
|
||||
long DrcvDelay = local.subtract(posnd).longValue();
|
||||
// System.out.println(DsndDelay+" "+DrcvDelay);
|
||||
|
||||
long rtt = DsndDelay + DrcvDelay;
|
||||
if (DsndDelay >= 0 && DrcvDelay >= 0) {
|
||||
monitor.recordUploadDelay(DsndDelay);
|
||||
monitor.recordDownloadDelay(DrcvDelay);
|
||||
//sysclk.adjustClock(Long128.valueOf( DsndDelay-DrcvDelay), 0.001);
|
||||
} else {
|
||||
adjnc.setDelta(adjnc.getDelta() + DsndDelayFactor);
|
||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
||||
long Dfallback = rtt / 2;
|
||||
if (Dfallback >= 0) {
|
||||
monitor.recordUploadDelay(Dfallback);
|
||||
monitor.recordDownloadDelay(Dfallback);
|
||||
}
|
||||
} else {
|
||||
if (DrcvDelayFactor < 0) {
|
||||
adjnc.setDelta(adjnc.getDelta() - DrcvDelayFactor);
|
||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
adjnc.getLock().unlock();
|
||||
// sysclk.adjustClock(Long128.valueOf( DsndDelay-DrcvDelay), 0.1);
|
||||
}
|
||||
|
||||
|
||||
tlock.unpark();
|
||||
updateUsedTime() ;
|
||||
if(reports!=null)
|
||||
reports.updateDial(monitor);
|
||||
break;
|
||||
case KLALBPacket.TESTN:
|
||||
break;
|
||||
@@ -330,12 +339,7 @@ public class Kperf implements Runnable{
|
||||
tcc.interrupt();
|
||||
}
|
||||
}
|
||||
private void updateUsedTime() {
|
||||
usedtime=System.nanoTime()-starttime;
|
||||
//System.out.println(usedtime+" "+totaltime);
|
||||
if(reports!=null)
|
||||
reports.testProcess(usedtime/(double)totaltime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -436,8 +440,7 @@ public class Kperf implements Runnable{
|
||||
|
||||
|
||||
public void startPerfing() {
|
||||
monitorUpdater=new MonitorUpdater();
|
||||
ThreadTool.makeVDaemonThread("线路性能采样线程", monitorUpdater).start();
|
||||
monitorUpdater= KLALBScheduler.getScheduler().scheduleWithFixedDelay(new MonitorUpdater(),1,1, TimeUnit.MILLISECONDS);
|
||||
ThreadTool.makeVDaemonThreadIfSupport("测速接收线程" ,this).start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.kne.cloud.network.perf;
|
||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||
|
||||
public interface KperfReports {
|
||||
public void testProcess(double d);
|
||||
public void testFinish();
|
||||
public void updateDial(SpeedAndTrafficAndDelayMonitorDataImpl mdt);
|
||||
public void uploadSpeedFinish(long uploadSpeed);
|
||||
|
||||
@@ -1,73 +1,87 @@
|
||||
package org.kne.cloud.network.perf;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.kne.cloud.network.ByteBufferAllocator;
|
||||
import org.kne.cloud.network.NetworkPacket;
|
||||
import org.kne.cloud.network.klalb.KLALBPacket;
|
||||
|
||||
public class TESTNPacket extends KLALBPacket {
|
||||
|
||||
private static final int HEADER_LENGTH=3;
|
||||
private static final int HEADER_LENGTH = 3;
|
||||
|
||||
// 核心:一个线程私有的 65535 字节大缓存,生命周期与线程同寿
|
||||
private static final ThreadLocal<ByteBuffer> BENCH_BUFFER =
|
||||
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
|
||||
|
||||
// 不再持有 ByteBuffer,只记录长度
|
||||
private int payloadLength;
|
||||
|
||||
private ByteBuffer dataBuffer;//=NetworkPacket.databufferpool_65535.borrow();
|
||||
@Override
|
||||
public long getTotalLength() {
|
||||
return HEADER_LENGTH+dataBuffer.limit();
|
||||
return HEADER_LENGTH + payloadLength;
|
||||
}
|
||||
|
||||
|
||||
// 发送端构造
|
||||
public TESTNPacket(int limit) {
|
||||
super(TESTN,HEADER_LENGTH);
|
||||
//dataBuffer.limit(limit);
|
||||
dataBuffer=NetworkPacket.bufferAllocator.allocate(limit);
|
||||
super(TESTN, HEADER_LENGTH);
|
||||
this.payloadLength = limit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ByteBuffer getDataBuffer() {
|
||||
return dataBuffer;
|
||||
// 接收端构造(从已有的 ByteBuffer 解析)
|
||||
public TESTNPacket(ByteBuffer bb) {
|
||||
super(bb, HEADER_LENGTH);
|
||||
this.payloadLength = klalbHeader.getChar(1);
|
||||
}
|
||||
|
||||
public int getPayloadLength() {
|
||||
return payloadLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
||||
klalbHeader.putChar(1, (char) dataBuffer.limit());
|
||||
// 1. 写入包头(包含 payloadLength)
|
||||
klalbHeader.putChar(1, (char) payloadLength);
|
||||
super.writeToChannel(dto);
|
||||
//System.out.println(dataBuffer);
|
||||
dto.write(dataBuffer.slice(0, dataBuffer.limit()));
|
||||
|
||||
// 2. 如果有 payload,借用 ThreadLocal 缓冲区并写出去
|
||||
if (payloadLength > 0) {
|
||||
ByteBuffer buf = BENCH_BUFFER.get();
|
||||
buf.clear();
|
||||
buf.limit(payloadLength); // 限制到指定长度
|
||||
|
||||
// 直接写出,里面的数据是上一次残留的或者全 0,对于烤机无所谓
|
||||
dto.write(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromChannel(ReadableByteChannel din) throws IOException {
|
||||
// 1. 读包头
|
||||
super.readFromChannel(din);
|
||||
int limit=klalbHeader.getChar(1);
|
||||
dataBuffer=NetworkPacket.bufferAllocator.allocate(limit);
|
||||
while(dataBuffer.hasRemaining()){
|
||||
if(din.read(dataBuffer)==-1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
}
|
||||
dataBuffer.flip();
|
||||
}
|
||||
this.payloadLength = klalbHeader.getChar(1);
|
||||
|
||||
public TESTNPacket(ByteBuffer bb) {
|
||||
super(bb,HEADER_LENGTH);
|
||||
}
|
||||
// 2. 如果有 payload,借用缓冲区接收数据
|
||||
if (payloadLength > 0) {
|
||||
ByteBuffer buf = BENCH_BUFFER.get();
|
||||
buf.clear();
|
||||
buf.limit(payloadLength);
|
||||
|
||||
// 循环读满(使用你现有的 KNEChannels 工具或手动循环)
|
||||
while (buf.hasRemaining()) {
|
||||
if (din.read(buf) == -1) {
|
||||
throw new EOFException("连接提前断开,未能读满 TESTN 载荷");
|
||||
}
|
||||
}
|
||||
// 数据读完直接丢弃,缓冲区不保存,下一次 clear() 时会自动覆盖
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TESTN["+dataBuffer.limit()+"]";
|
||||
return "TESTN[" + payloadLength + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import java.net.Inet6Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -35,6 +36,7 @@ import org.kne.cloud.network.monitor.MonitorData;
|
||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorData;
|
||||
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl;
|
||||
import org.kne.io.KNEChannels;
|
||||
import org.kne.membandboost.MembandBoost;
|
||||
|
||||
public class KLALBRoutingProtocol extends Thread{
|
||||
@@ -211,20 +213,15 @@ public class KLALBRoutingProtocol extends Thread{
|
||||
while(true) {
|
||||
|
||||
try {
|
||||
byte[]ca=MembandBoost.allocateUninitializedByteArray(65535);
|
||||
DatagramPacket dgp=new DatagramPacket(ca, ca.length);
|
||||
ds.receive(dgp);
|
||||
//System.out.println(Arrays.toString( Arrays.copyOf( dgp.getData(),dgp.getLength())));
|
||||
ByteArrayInputStream bi=new ByteArrayInputStream(dgp.getData(),0,dgp.getLength());
|
||||
KLALBRoutingProtocolPacket kp=KLALBRoutingProtocolPacket.readKLALBPacketFromChannel(Channels.newChannel(bi));
|
||||
KLALBRoutingProtocolPacket kp=receivePacket();
|
||||
|
||||
switch(kp.getType()) {
|
||||
case KLALBRoutingProtocolPacket.RINFO_REQ:
|
||||
RouterInfo rifr=netmap.get(router.getLocator().getAddress());
|
||||
if(debug)
|
||||
System.out.println("get Request from:"+dgp.getSocketAddress());
|
||||
System.out.println("get Request from:"+kp.getFrom());
|
||||
if(rifr!=null) {
|
||||
writePacket( new RouterInfoPacket( rifr,false,-1), dgp.getSocketAddress());
|
||||
writePacket( new RouterInfoPacket( rifr,false,-1), kp.getFrom());
|
||||
if(debug)
|
||||
System.out.println("response router info:"+rifr);
|
||||
}else {
|
||||
@@ -246,7 +243,7 @@ public class KLALBRoutingProtocol extends Thread{
|
||||
netmap.put(rif.getLocator().getAddress(), rif);
|
||||
noticeUpdate();
|
||||
if(rifp.isFlood()) {
|
||||
floodPacket( dgp.getSocketAddress(), rifp);
|
||||
floodPacket( kp.getFrom(), rifp);
|
||||
|
||||
}
|
||||
|
||||
@@ -259,7 +256,7 @@ public class KLALBRoutingProtocol extends Thread{
|
||||
break;
|
||||
case KLALBRoutingProtocolPacket.JSON_DATA:
|
||||
JsonDataPacket data=(JsonDataPacket) kp;
|
||||
receivers.forEach((v)->{v.accept(dgp.getSocketAddress(),data);});
|
||||
receivers.forEach((v)->{v.accept(kp.getFrom(),data);});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -276,7 +273,32 @@ public class KLALBRoutingProtocol extends Thread{
|
||||
}
|
||||
}
|
||||
}
|
||||
private static final ThreadLocal<ByteBuffer> LSDB_RX_BUFFER =
|
||||
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
|
||||
|
||||
private KLALBRoutingProtocolPacket receivePacket() throws IOException {
|
||||
// 2. 获取并重置缓冲区
|
||||
ByteBuffer bbf = LSDB_RX_BUFFER.get();
|
||||
bbf.clear();
|
||||
|
||||
// 3. 构造 DatagramPacket(注意这里要传底层 array 和 capacity)
|
||||
DatagramPacket dgp = new DatagramPacket(bbf.array(), bbf.capacity());
|
||||
|
||||
// 4. 阻塞接收
|
||||
ds.receive(dgp);
|
||||
|
||||
// 5. 限制缓冲区范围到实际收到的长度
|
||||
bbf.limit(dgp.getLength());
|
||||
bbf.position(0);
|
||||
|
||||
// 6. 直接用 KNEChannels 包装 ByteBuffer,避免 ByteArrayInputStream
|
||||
KLALBRoutingProtocolPacket kp = KLALBRoutingProtocolPacket.readKLALBPacketFromChannel(
|
||||
KNEChannels.newReadableChannel(bbf)
|
||||
);
|
||||
if(kp!=null)
|
||||
kp.setFrom(dgp.getSocketAddress());
|
||||
return kp;
|
||||
}
|
||||
private void floodPacket(SocketAddress except,RouterInfoPacket rifp) throws IOException {
|
||||
long asn=rifp.getASN();
|
||||
List<Neighbor>ln= router.getNeighbors();
|
||||
@@ -304,20 +326,34 @@ public class KLALBRoutingProtocol extends Thread{
|
||||
public void sendJsonPacketToAddress(JsonDataPacket pkt,SocketAddress dest) throws IOException {
|
||||
writePacket(pkt,dest);
|
||||
}
|
||||
// 1. 在类成员变量处定义一个 64KB 的 ThreadLocal 缓冲区
|
||||
// 注意:这里依然使用 65535,因为你说 LSDB 同步可能需要这么大
|
||||
private static final ThreadLocal<ByteBuffer> LSDB_TX_BUFFER =
|
||||
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
|
||||
|
||||
private void writePacket(KLALBRoutingProtocolPacket pkt,SocketAddress dest) throws IOException {
|
||||
ByteArrayOutputStream bos=new ByteArrayOutputStream(65535);
|
||||
KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(Channels.newChannel(bos),pkt);
|
||||
byte[]to=bos.toByteArray();
|
||||
DatagramPacket dgpx=new DatagramPacket(to,to.length);
|
||||
private void writePacket(KLALBRoutingProtocolPacket pkt, SocketAddress dest) throws IOException {
|
||||
// 2. 从 ThreadLocal 获取,并清空状态
|
||||
ByteBuffer bbf = LSDB_TX_BUFFER.get();
|
||||
bbf.clear();
|
||||
|
||||
// 3. 使用 KNEChannels 绑定到 ByteBuffer,直接写入
|
||||
// 这避免了 ByteArrayOutputStream 内部的动态扩容和拷贝
|
||||
KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(KNEChannels.newWritableChannel(bbf), pkt);
|
||||
|
||||
// 4. 翻转,准备读取数据
|
||||
bbf.flip();
|
||||
|
||||
// 5. 直接拿底层的 byte[] 和真实的 limit 发送
|
||||
DatagramPacket dgpx = new DatagramPacket(bbf.array(), bbf.limit());
|
||||
dgpx.setSocketAddress(dest);
|
||||
|
||||
sendLock.lock();
|
||||
try {
|
||||
ds.send(dgpx);
|
||||
}catch(BindException e) {
|
||||
} catch (BindException e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Cannot assign:"+dest);
|
||||
}finally {
|
||||
System.err.println("Cannot assign:" + dest);
|
||||
} finally {
|
||||
sendLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||