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>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="lib" path="lib/gson-2.1.jar"/>
|
<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/ini4j.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/toml4j-0.7.1.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/KNElib1.0.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/KNEOptimize.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/JavaTUN0.3.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/KNEOptimize.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="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="module" value="true"/>
|
<attribute name="module" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="lib" path="lib/jfreechart-1.5.3.jar"/>
|
<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="lib" path="lib/jfreechart-1.5.3-sources.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</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">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/dashboard" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -250,5 +250,6 @@
|
|||||||
</orderEntry>
|
</orderEntry>
|
||||||
<orderEntry type="jdk" jdkName="jdk-26.0.1" jdkType="JavaSDK" />
|
<orderEntry type="jdk" jdkName="jdk-26.0.1" jdkType="JavaSDK" />
|
||||||
<orderEntry type="library" name="jfreechart-1.5.3" level="project" />
|
<orderEntry type="library" name="jfreechart-1.5.3" level="project" />
|
||||||
|
<orderEntry type="library" name="jctools-core-jdk11-4.0.7" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</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 |
@@ -4,9 +4,9 @@ language=Language
|
|||||||
basicsettings=Basic settings
|
basicsettings=Basic settings
|
||||||
ipv6addr=IPv6 address
|
ipv6addr=IPv6 address
|
||||||
devicename=Device name
|
devicename=Device name
|
||||||
devicedescription=Device description
|
devicedescription=Device description
|
||||||
dnsserver=DNS server
|
dnsserver=DNS server
|
||||||
extraroutes=Extra routes
|
extraroutes=Extra routes
|
||||||
asnumber=AS number
|
asnumber=AS number
|
||||||
tcplistening=TCP listening
|
tcplistening=TCP listening
|
||||||
udplistening=UDP listening
|
udplistening=UDP listening
|
||||||
@@ -111,9 +111,17 @@ performancesettings=Performance settings
|
|||||||
performancestrategy=Performance strategy
|
performancestrategy=Performance strategy
|
||||||
singlecore=Single-Core - Cache Affinity First (Best energy/performance ratio, for low-power & cloud)
|
singlecore=Single-Core - Cache Affinity First (Best energy/performance ratio, for low-power & cloud)
|
||||||
multifill=Multi-Core - Fill Cores Sequentially (Recommended for general-purpose physical servers)
|
multifill=Multi-Core - Fill Cores Sequentially (Recommended for general-purpose physical servers)
|
||||||
multiscatter=Multi-Core - Spread Load Evenly (Optimized for multi-socket NUMA architectures)
|
multiscatter=Multi-Core - Spread Load Evenly (Optimized for multi-socket NUMA architectures)
|
||||||
webapisettings=Web API settings
|
webapisettings=Web API settings
|
||||||
enablewebapi=Enable Web API
|
enablewebapi=Enable Web API
|
||||||
weblistenaddr=Web API listen address
|
weblistenaddr=Web API listen address
|
||||||
invaildweblistenaddr=Invalid Web API listen address
|
invaildweblistenaddr=Invalid Web API listen address
|
||||||
enabletun=Enable TUN adapter
|
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
|
||||||
@@ -116,4 +116,12 @@ webapisettings=Web API 设置
|
|||||||
enablewebapi=启用 Web API
|
enablewebapi=启用 Web API
|
||||||
weblistenaddr=Web API 监听地址:端口
|
weblistenaddr=Web API 监听地址:端口
|
||||||
invaildweblistenaddr=无效的 Web API 监听地址:端口
|
invaildweblistenaddr=无效的 Web API 监听地址:端口
|
||||||
enabletun=启用TUN虚拟网卡
|
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.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.kne.math.Long128;
|
import org.kne.math.Long128;
|
||||||
|
|
||||||
@@ -256,4 +259,27 @@ public class NTPTimestamps {
|
|||||||
.setBit(63);
|
.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.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -148,21 +150,39 @@ public class IPMulticastDiscovery implements Closeable, AutoCloseable {
|
|||||||
}
|
}
|
||||||
}).start();
|
}).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 {
|
private MultiProtocolSocketAddress receive() throws IOException {
|
||||||
byte[] b = new byte[65535];
|
ByteBuffer bbf = RX_BUFFER.get();
|
||||||
DatagramPacket dp = new DatagramPacket(b, b.length);
|
bbf.clear(); // 重置 position=0, limit=2048
|
||||||
|
|
||||||
|
// 借用底层数组
|
||||||
|
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||||
soc.receive(dp);
|
soc.receive(dp);
|
||||||
ByteArrayInputStream bis = new ByteArrayInputStream(b, 0, dp.getLength());
|
|
||||||
DataInputStream dis = new DataInputStream(bis);
|
// 限制可读范围
|
||||||
String val = dis.readUTF();
|
int length = dp.getLength();
|
||||||
long h=dis.readLong();
|
bbf.limit(length);
|
||||||
long l=dis.readLong();
|
|
||||||
UUID uid=new UUID(h, l);
|
// 直接读 UTF 字符串 (不用 DataInputStream)
|
||||||
dis.close();
|
// 读取前两个字节的长度,然后创建 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);
|
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(debug) {
|
||||||
if(uid.equals(selfUUID)) {
|
if(uid.equals(selfUUID)) {
|
||||||
@@ -176,15 +196,23 @@ public class IPMulticastDiscovery implements Closeable, AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void send(MultiProtocolSocketAddress multiProtocolSocketAddress) throws IOException {
|
private void send(MultiProtocolSocketAddress multiProtocolSocketAddress) throws IOException {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteBuffer bbf = TX_BUFFER.get();
|
||||||
DataOutputStream dops = new DataOutputStream(baos);
|
bbf.clear(); // 重置
|
||||||
dops.writeUTF(multiProtocolSocketAddress.toString());
|
|
||||||
dops.writeLong(selfUUID.getMostSignificantBits());
|
// 写字符串 (长度 + 字节)
|
||||||
dops.writeLong(selfUUID.getLeastSignificantBits());
|
byte[] strBytes = multiProtocolSocketAddress.toString().getBytes(StandardCharsets.UTF_8);
|
||||||
dops.close();
|
bbf.putShort((short) strBytes.length);
|
||||||
byte[] b = baos.toByteArray();
|
bbf.put(strBytes);
|
||||||
DatagramPacket dp = new DatagramPacket(b, b.length, group);
|
|
||||||
|
// 写 UUID
|
||||||
|
bbf.putLong(selfUUID.getMostSignificantBits());
|
||||||
|
bbf.putLong(selfUUID.getLeastSignificantBits());
|
||||||
|
|
||||||
|
bbf.flip(); // 准备读取
|
||||||
|
|
||||||
|
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit(), group);
|
||||||
soc.send(dp);
|
soc.send(dp);
|
||||||
|
|
||||||
if(debug)
|
if(debug)
|
||||||
System.out.println(ninterface.getDisplayName()+" 发送广播:"+ multiProtocolSocketAddress +" "+group+" "+selfUUID);
|
System.out.println(ninterface.getDisplayName()+" 发送广播:"+ multiProtocolSocketAddress +" "+group+" "+selfUUID);
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,13 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
|||||||
|
|
||||||
private Consumer<Long> windowControlConsumer;
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
|
||||||
private long MIN_RTTVAR = 5000000L;
|
|
||||||
private volatile long RTTMin = 1000000000L;
|
private volatile long RTTMin = 1000000000L;
|
||||||
private volatile long RTTVar = 1000000000L;
|
|
||||||
private volatile long RTTAvg = 1000000000L;
|
|
||||||
private volatile long RTTAvg2 = 1000000000L;
|
private volatile long RTTAvg2 = 1000000000L;
|
||||||
private volatile long RTTTotal = 0;
|
private volatile long RTTTotal = 0;
|
||||||
private volatile long RTTCount = 0;
|
private volatile long RTTCount = 0;
|
||||||
private volatile long RTO = 1000000000L;
|
|
||||||
|
|
||||||
|
private RTTEstimator rttEstimator=new RTTEstimator();
|
||||||
|
|
||||||
|
|
||||||
private volatile long window=MIN_WINDOW;
|
private volatile long window=MIN_WINDOW;
|
||||||
@@ -54,10 +53,7 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
|||||||
} else {
|
} else {
|
||||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||||
}
|
}
|
||||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
rttEstimator.putRTT(latencyns);
|
||||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
|
||||||
|
|
||||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
|
||||||
|
|
||||||
RTTTotal += latencyns;
|
RTTTotal += latencyns;
|
||||||
RTTCount++;
|
RTTCount++;
|
||||||
@@ -93,13 +89,13 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
public void putLoss(long packetSize, long lossns) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRTO() {
|
public long getRTO() {
|
||||||
return RTO;
|
return rttEstimator.getRTO();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -136,4 +132,29 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
|||||||
return "BBR";
|
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 reset();
|
||||||
public void setWindowControlConsumer(Consumer<Long>windowControlConsumer);
|
public void setWindowControlConsumer(Consumer<Long>windowControlConsumer);
|
||||||
public void putAck(long packetSize,long RTTns,boolean ecn);
|
public void putAck(long packetSize,long RTTns,boolean ecn);
|
||||||
default public void putAck(long packetSize,long RTTns,long OWDup,boolean ecn) {
|
public void putLoss(long packetSize,long lossns);
|
||||||
putAck(packetSize,RTTns,ecn);
|
|
||||||
}
|
|
||||||
public void putLoss(long packetSize,long lossns,int losscounter);
|
|
||||||
public void setCurrentWindowUsed(long maxwindow);
|
public void setCurrentWindowUsed(long maxwindow);
|
||||||
public void setCurrentBandwidth(long bandwidth);
|
public void setCurrentBandwidth(long bandwidth);
|
||||||
public long getRTO();
|
public long getRTO();
|
||||||
public String getName();
|
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 Consumer<Long> windowControlConsumer;
|
||||||
|
|
||||||
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
|
||||||
private long MIN_RTTVAR = 100000000L;
|
|
||||||
private volatile long RTTMin = 1000000000L;
|
private volatile long RTTMin = 1000000000L;
|
||||||
private volatile long RTTVar = 1000000000L;
|
|
||||||
private volatile long RTTAvg = 1000000000L;
|
|
||||||
private double ECNAvg2 = 0L;
|
private double ECNAvg2 = 0L;
|
||||||
private double alpha=0;
|
private double alpha=0;
|
||||||
private volatile AtomicLong ECNSize = new AtomicLong(0);
|
private volatile AtomicLong ECNSize = new AtomicLong(0);
|
||||||
private volatile AtomicLong TotalSize = 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;
|
private volatile long window=MIN_WINDOW;
|
||||||
@@ -54,14 +51,7 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
} else {
|
} else {
|
||||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||||
}
|
}
|
||||||
if (firstUpdate.compareAndSet(true, false)) {
|
rttEstimator.putRTT(latencyns);
|
||||||
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
|
|
||||||
|
|
||||||
if(ecn) {
|
if(ecn) {
|
||||||
ECNSize.addAndGet(packetSize);
|
ECNSize.addAndGet(packetSize);
|
||||||
@@ -88,7 +78,7 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
if(windowUsed*3L>=congressWindowSize) {
|
if(windowUsed*3L>=congressWindowSize) {
|
||||||
congressWindowSize+=4000;
|
congressWindowSize+=4096;
|
||||||
updateWindowSize();
|
updateWindowSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,13 +99,13 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
public void putLoss(long packetSize, long lossns) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRTO() {
|
public long getRTO() {
|
||||||
return RTO;
|
return rttEstimator.getRTO();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -133,6 +123,15 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
return "DCTCP";
|
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 setUpperDelayBound(double upper);
|
||||||
public void setLowerDelayBound(double lower);
|
public void setLowerDelayBound(double lower);
|
||||||
public void setBurstLimit(double limit);
|
public void setBurstLimit(double limit);
|
||||||
|
public double getUpperDelayBound( );
|
||||||
|
public double getLowerDelayBound();
|
||||||
|
public double getBurstLimit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.kne.cloud.network.congestion;
|
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.cloud.network.ThreadTool;
|
||||||
import org.kne.opencl64.Releaser;
|
import org.kne.opencl64.Releaser;
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ class MpscMessageBatcherReleaser<T> extends Releaser<MpscMessageBatcher0<T>> {
|
|||||||
|
|
||||||
class MpscMessageBatcher0<T> implements Runnable, MessageBatcher<T> {
|
class MpscMessageBatcher0<T> implements Runnable, MessageBatcher<T> {
|
||||||
|
|
||||||
private final MpscArrayQueue<T> queue;
|
private final MessagePassingQueue<T> queue;
|
||||||
private final int batchSize;
|
private final int batchSize;
|
||||||
private final long maxDelay;
|
private final long maxDelay;
|
||||||
private volatile Consumer<List<T>> consumer;
|
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) {
|
public MpscMessageBatcher0(int batchSize, long maxDelay, int queueCapacity) {
|
||||||
this.batchSize = batchSize;
|
this.batchSize = batchSize;
|
||||||
this.maxDelay = maxDelay;
|
this.maxDelay = maxDelay;
|
||||||
this.queue = new MpscArrayQueue<>(queueCapacity);
|
this.queue = new MpscVarHandleArrayQueue<>(queueCapacity);
|
||||||
|
|
||||||
this.batchThread = ThreadTool.makeVDaemonThread("MpscMessageBatcher", this);
|
this.batchThread = ThreadTool.makeVDaemonThread("MpscMessageBatcher", this);
|
||||||
this.batchThread.start();
|
this.batchThread.start();
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class NOCongestionAlgorithm implements CongestionAlgorithm{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
public void putLoss(long packetSize, long lossns) {
|
||||||
// TODO 自动生成的方法存根
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -63,4 +63,14 @@ public class NOCongestionAlgorithm implements CongestionAlgorithm{
|
|||||||
return "NO";
|
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.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
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.atomic.AtomicLong;
|
||||||
import java.util.concurrent.locks.Condition;
|
import java.util.concurrent.locks.Condition;
|
||||||
import java.util.concurrent.locks.Lock;
|
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.NetworkPacket;
|
||||||
import org.kne.cloud.network.ThreadTool;
|
import org.kne.cloud.network.ThreadTool;
|
||||||
|
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||||
import org.kne.cloud.network.klalb.SendItem;
|
import org.kne.cloud.network.klalb.SendItem;
|
||||||
import org.kne.concurrent.ThreadParker;
|
import org.kne.concurrent.ThreadParker;
|
||||||
|
|
||||||
public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Closeable, AutoCloseable {
|
public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Closeable, AutoCloseable {
|
||||||
|
private final ScheduledFuture<?> checkerTask;
|
||||||
private ThreadParker tp=new ThreadParker();
|
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 AtomicLong sendWindowUsed=new AtomicLong(0);
|
||||||
//private LongAdder sendWindowUsed = new LongAdder();
|
//private LongAdder sendWindowUsed = new LongAdder();
|
||||||
|
|
||||||
@@ -51,13 +56,12 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SendPacketSlidingWindow(CongestionAlgorithm algorithm, long windowSize, int headerCalibrate,
|
public SendPacketSlidingWindow(CongestionAlgorithm algorithm, long windowSize, int headerCalibrate,
|
||||||
boolean removeAtResend) {
|
boolean removeAtResend) {
|
||||||
this.headerCalibrate = headerCalibrate;
|
this.headerCalibrate = headerCalibrate;
|
||||||
this.removeAtResend = removeAtResend;
|
this.removeAtResend = removeAtResend;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
this.windowSize=windowSize;
|
this.windowSize=windowSize;
|
||||||
Thread t = ThreadTool.makeVThread("重路由计时器线程", checker);
|
this.checkerTask=KLALBScheduler.getScheduler().scheduleWithFixedDelay(checker,1,1, TimeUnit.MILLISECONDS);
|
||||||
t.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getWindowSize() {
|
public long getWindowSize() {
|
||||||
@@ -106,7 +110,7 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
|||||||
boolean congress = sendWindowUsed.get() > windowSize ;
|
boolean congress = sendWindowUsed.get() > windowSize ;
|
||||||
return congress;
|
return congress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForAvaliable() throws SocketException {
|
public void waitForAvaliable() throws SocketException {
|
||||||
while(isCongestion()) {
|
while(isCongestion()) {
|
||||||
if(closed) {
|
if(closed) {
|
||||||
@@ -119,28 +123,27 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
|||||||
waitForAvaliable();
|
waitForAvaliable();
|
||||||
put(sequence,packet);
|
put(sequence,packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(K sequence, V packet) {
|
public void put(K sequence, V packet) {
|
||||||
SendItem<V> newitem = new SendItem<V>(packet,headerCalibrate);
|
SendItem<V> newitem = new SendItem<V>(packet,headerCalibrate);
|
||||||
SendItem<V> old = sendMap.put(sequence, newitem);
|
SendItem<V> old = sendMap.put(sequence, newitem);
|
||||||
long dx=0;
|
long dx=0;
|
||||||
if (old != null) {
|
if (old != null) {
|
||||||
dx=-old.getPacketLength() ;
|
dx=-old.getPacketLength() ;
|
||||||
}
|
}
|
||||||
long newWindow =sendWindowUsed.addAndGet(newitem.getPacketLength() +dx);
|
long newWindow =sendWindowUsed.addAndGet(newitem.getPacketLength() +dx);
|
||||||
algorithm.setCurrentWindowUsed(newWindow);
|
algorithm.setCurrentWindowUsed(newWindow);
|
||||||
}
|
}
|
||||||
public V ack(K sequence) {
|
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;
|
SendItem<V> ipv6;
|
||||||
if ((ipv6 = sendMap.remove(sequence)) != null) {
|
if ((ipv6 = sendMap.remove(sequence)) != null) {
|
||||||
long newWindow =sendWindowUsed.addAndGet(-ipv6.getPacketLength() );
|
long newWindow =sendWindowUsed.addAndGet(-ipv6.getPacketLength() );
|
||||||
algorithm.setCurrentWindowUsed(newWindow);
|
algorithm.setCurrentWindowUsed(newWindow);
|
||||||
long RTTC = System.nanoTime() - ipv6.getSendtime();
|
algorithm.putAck(ipv6.getPacketLength(), RTTns, ecn);
|
||||||
algorithm.putAck(ipv6.getPacketLength(), RTTC, ecn);
|
|
||||||
tp.unpark();
|
tp.unpark();
|
||||||
// System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
// System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
||||||
Lock lockx = lock;
|
Lock lockx = lock;
|
||||||
@@ -162,73 +165,59 @@ 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 {
|
private class ResendChecker implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!closed) {
|
try {
|
||||||
|
if (closed) {
|
||||||
Collection<SendItem<V>> vals = sendMap.values();
|
checkerTask.cancel(false);
|
||||||
for (Iterator<SendItem<V>> iterator = vals.iterator(); iterator.hasNext();) {
|
// 清理资源
|
||||||
SendItem<V> sitm = (SendItem<V>) iterator.next();
|
if (closingConsumer != null) {
|
||||||
long current = System.nanoTime();
|
for (SendItem<V> item : sendMap.values()) {
|
||||||
if (current - sitm.getSendtime() > algorithm.getRTO()) {
|
closingConsumer.accept(item.getPacket());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(2);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
// 清理资源
|
|
||||||
if (closingConsumer != null) {
|
|
||||||
for (SendItem<V> item : sendMap.values()) {
|
|
||||||
closingConsumer.accept(item.getPacket());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendMap.clear();
|
|
||||||
sendWindowUsed.set(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,4 +265,4 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,9 @@ package org.kne.cloud.network.congestion;
|
|||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.monitor.DelaySampler;
|
||||||
|
import org.kne.concurrent.SpinLock;
|
||||||
|
|
||||||
public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCongestionAlgorithm {
|
public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCongestionAlgorithm {
|
||||||
|
|
||||||
// 可配置的时延膨胀比上下限 - Vegas2.0核心参数
|
// 可配置的时延膨胀比上下限 - Vegas2.0核心参数
|
||||||
@@ -11,29 +14,26 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
|
|
||||||
private static final long BURST_TIME = 2000000L;
|
private static final long BURST_TIME = 2000000L;
|
||||||
private static final long BIAS = 1000000L;
|
private static final long BIAS = 1000000L;
|
||||||
private static long MIN_WINDOW = 16384;
|
private static long MIN_WINDOW = 8192;
|
||||||
|
|
||||||
|
|
||||||
private Consumer<Long> windowControlConsumer;
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
|
||||||
private long MIN_RTTVAR = 30000000L;
|
private volatile long RTTCurr = 1000000000L; // RTT
|
||||||
private volatile long RTTMin = 1000000000L; // BaseRTT
|
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 RTTAvg2 = 1000000000L; // 当前平滑RTT
|
||||||
private volatile long RTTTotal = 0;
|
private volatile long RTTTotal = 0;
|
||||||
private volatile long RTTCount = 0;
|
private volatile long RTTCount = 0;
|
||||||
private volatile long RTO = 1000000000L;
|
|
||||||
|
|
||||||
|
|
||||||
private volatile long OWDTotal = 0;
|
private RTTEstimator rttEstimator=new RTTEstimator();
|
||||||
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 window = MIN_WINDOW;
|
||||||
private volatile long window2 = MIN_WINDOW;
|
private volatile long window2 = MIN_WINDOW;
|
||||||
private volatile long maxwindow = 99999999999L;
|
private volatile long maxwindow = 99999999999L;
|
||||||
|
|
||||||
|
private final SpinLock slock=new SpinLock();
|
||||||
|
|
||||||
public Vegas2CongestionAlgorithm() {
|
public Vegas2CongestionAlgorithm() {
|
||||||
reset();
|
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
|
@Override
|
||||||
public void putAck(long packetSize, long RTTns, boolean ecn) {
|
public void putAck(long packetSize, long RTTns, boolean ecn) {
|
||||||
if(RTTns<0) {
|
if(RTTns<0) {
|
||||||
throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
|
throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
|
||||||
}
|
}
|
||||||
|
this.RTTCurr=RTTns;
|
||||||
// 处理ECN信号 - 将其视为强烈的拥塞信号
|
// 处理ECN信号 - 将其视为强烈的拥塞信号
|
||||||
if (ecn) {
|
if (ecn) {
|
||||||
// 当收到ECN时,更激进地减少窗口
|
// 当收到ECN时,更激进地减少窗口
|
||||||
@@ -166,64 +73,54 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
windowControlConsumer.accept(window2);
|
windowControlConsumer.accept(window2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新最小RTT(BaseRTT)
|
|
||||||
if (RTTns <= RTTMin) {
|
|
||||||
RTTMin = RTTns;
|
|
||||||
} else {
|
|
||||||
// 缓慢适应:当网络路径真正变化时,BaseRTT应能缓慢更新
|
|
||||||
// 这里使用极慢的衰减因子,只有在持续观测到更低RTT时才快速更新
|
|
||||||
RTTMin = (RTTMin * 999 + RTTns) / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新平滑RTT估计
|
// 更新平滑RTT估计
|
||||||
|
rttEstimator.putRTT(RTTns);
|
||||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - RTTns)) / 4;
|
|
||||||
RTTAvg = (RTTAvg * 7 + RTTns) / 8;
|
|
||||||
|
|
||||||
|
|
||||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);
|
|
||||||
|
|
||||||
RTTTotal += RTTns;
|
RTTTotal += RTTns;
|
||||||
RTTCount++;
|
RTTCount++;
|
||||||
|
if(slock.tryLock())try {
|
||||||
long curr = System.nanoTime();
|
long curr = System.nanoTime();
|
||||||
// 每个RTT周期调整一次窗口(使用当前估计的RTT)
|
// 每个RTT周期调整一次窗口(使用当前估计的RTT)
|
||||||
if (curr - RTTstartTime > Math.max(BIAS, 2*RTTMin)) {
|
if (curr - RTTstartTime > Math.max(BIAS, 2 * RTTMin)) {
|
||||||
long RTTCountx=RTTCount;
|
rttEstimator.update();
|
||||||
if (RTTCountx > 0) {
|
RTTMin = rttEstimator.getBaseRTT();
|
||||||
long currentRTT = RTTTotal / RTTCountx;
|
|
||||||
//RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4; // 平滑当前RTT
|
|
||||||
RTTAvg2=currentRTT;
|
long RTTCountx = RTTCount;
|
||||||
RTTTotal = 0;
|
if (RTTCountx > 0) {
|
||||||
RTTCount = 0;
|
long currentRTT = RTTTotal / RTTCountx;
|
||||||
|
//RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4; // 平滑当前RTT
|
||||||
|
RTTAvg2 = currentRTT;
|
||||||
|
RTTTotal = 0;
|
||||||
|
RTTCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== Vegas2.0核心逻辑 ==================
|
||||||
|
// 1. 计算时延膨胀比
|
||||||
|
double delayRatio = (double) RTTAvg2 / (double) Math.max(BIAS, RTTMin);
|
||||||
|
//System.out.println(delayRatio+" "+RTTAvg2/1000000.0+" "+RTTMin/1000000.0);
|
||||||
|
// 2. 基于比值的窗口调整(取代原来的基于差值的调整)
|
||||||
|
if (delayRatio > delayUpperBound) {
|
||||||
|
// 时延过高:减小窗口,减少幅度与超标程度成正比
|
||||||
|
window2 = window2 - 4096;
|
||||||
|
} else if (delayRatio < delayLowerBound) {
|
||||||
|
// 时延过低:增大窗口,增加幅度与低于目标程度成正比
|
||||||
|
window2 = window2 + 4096;
|
||||||
|
} else {
|
||||||
|
//window2=window2+4096
|
||||||
|
}
|
||||||
|
// ===================================================
|
||||||
|
|
||||||
|
|
||||||
|
updateWindowSize();
|
||||||
|
RTTstartTime = curr;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}finally{
|
||||||
// ================== Vegas2.0核心逻辑 ==================
|
slock.unlock();
|
||||||
// 1. 计算时延膨胀比
|
|
||||||
double delayRatio = (double) RTTAvg2 / (double) Math.max(BIAS, RTTMin);
|
|
||||||
//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;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,12 +142,12 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
public void putLoss(long packetSize, long lossns) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRTO() {
|
public long getRTO() {
|
||||||
return RTO;
|
return rttEstimator.getRTO();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -269,12 +166,14 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getBaseRTT() {
|
public long getBaseRTT() {
|
||||||
return RTTMin;
|
return rttEstimator.getBaseRTT();
|
||||||
}
|
}
|
||||||
|
public long getAvgRTT() {
|
||||||
public long getCurrentRTT() {
|
|
||||||
return RTTAvg2;
|
return RTTAvg2;
|
||||||
}
|
}
|
||||||
|
public long getCurrentRTT() {
|
||||||
|
return RTTCurr;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUpperDelayBound(double upper) {
|
public void setUpperDelayBound(double upper) {
|
||||||
@@ -295,4 +194,19 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
return "Vegas2";
|
return "Vegas2";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getUpperDelayBound() {
|
||||||
|
return delayUpperBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLowerDelayBound() {
|
||||||
|
return delayLowerBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBurstLimit() {
|
||||||
|
return burstLimit;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,13 +14,20 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
|||||||
|
|
||||||
private SRv6Router srv6Router;
|
private SRv6Router srv6Router;
|
||||||
private final boolean loopback;
|
private final boolean loopback;
|
||||||
|
|
||||||
|
private final boolean filter;
|
||||||
|
|
||||||
|
|
||||||
public AbstractIPv6NetworkLink(boolean loopback) {
|
public AbstractIPv6NetworkLink(boolean loopback) {
|
||||||
super();
|
super();
|
||||||
this.loopback = loopback;
|
this.loopback = loopback;
|
||||||
|
this.filter = false;
|
||||||
}
|
}
|
||||||
|
public AbstractIPv6NetworkLink(boolean loopback, boolean filter) {
|
||||||
|
super();
|
||||||
|
this.loopback = loopback;
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
public SRv6Router getSrv6Router() {
|
public SRv6Router getSrv6Router() {
|
||||||
return srv6Router;
|
return srv6Router;
|
||||||
@@ -63,6 +70,8 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> receiveConsumer;
|
private BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> receiveConsumer;
|
||||||
|
|
||||||
|
private Supplier<Long> costSupplier;
|
||||||
@Override
|
@Override
|
||||||
public void setReceiveConsumer(BiConsumer<IPv6NetworkLink,Supplier< IPv6Packet>> receiveConsumer) {
|
public void setReceiveConsumer(BiConsumer<IPv6NetworkLink,Supplier< IPv6Packet>> receiveConsumer) {
|
||||||
this.receiveConsumer = receiveConsumer;
|
this.receiveConsumer = receiveConsumer;
|
||||||
@@ -73,6 +82,14 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
|||||||
return loopback;
|
return loopback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Supplier<Long> getCostSupplier() {
|
||||||
|
return costSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCostSupplier(Supplier<Long> costSupplier) {
|
||||||
|
this.costSupplier = costSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RouteItem> getRouteItems() {
|
public List<RouteItem> getRouteItems() {
|
||||||
List<RouteItem> rlist = new ArrayList<>();
|
List<RouteItem> rlist = new ArrayList<>();
|
||||||
@@ -86,16 +103,21 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
|||||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
|
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
|
||||||
Neighbor addresses = (Neighbor) iteratorx.next();
|
Neighbor addresses = (Neighbor) iteratorx.next();
|
||||||
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
|
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);
|
rlist.add(ri);
|
||||||
|
|
||||||
RouteItem ris = new RouteItem(addresses.getLocator(),
|
RouteItem ris = new RouteItem(addresses.getLocator(),
|
||||||
addresses.getLocator().getAddress(), this, RouteItem.SRv6_ENDSID, 13, 128,
|
addresses.getLocator().getAddress(), this, RouteItem.SRv6_ENDSID, 13, 128,
|
||||||
null, "D");
|
costSupplier, "D");
|
||||||
rlist.add(ris);
|
rlist.add(ris);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rlist;
|
return rlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFilter() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ public final class IPv6Address implements Comparable<IPv6Address> {
|
|||||||
((long)(bytes[15] & 0xFF));
|
((long)(bytes[15] & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IPv6Address(String string) throws UnknownHostException {
|
||||||
|
this((Inet6Address) Inet6Address.getByName(string));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从两个long创建IPv6地址
|
* 从两个long创建IPv6地址
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -67,7 +67,16 @@ public class IPv6AddressGroup implements Comparable<IPv6AddressGroup>{
|
|||||||
prefixLength=in.read();
|
prefixLength=in.read();
|
||||||
}
|
}
|
||||||
public boolean checkMatch(IPv6Address address2) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,5 +29,6 @@ public interface IPv6NetworkLink {
|
|||||||
public void setReceiveConsumer(BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> srhReceive);
|
public void setReceiveConsumer(BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> srhReceive);
|
||||||
public void addIPv6LinkStateListener(IPv6LinkStateListener listener);
|
public void addIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||||
public void removeIPv6LinkStateListener(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);
|
private AtomicInteger rerouteCounter = new AtomicInteger(0);
|
||||||
|
|
||||||
public AtomicInteger getRerouteCounter() {
|
public AtomicInteger getRouteCounter() {
|
||||||
return rerouteCounter;
|
return rerouteCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
|||||||
public static final String DIRECT="Direct";
|
public static final String DIRECT="Direct";
|
||||||
public static final String SRv6_ENDSID="SRv6 ENDSID";
|
public static final String SRv6_ENDSID="SRv6 ENDSID";
|
||||||
public static final String SRv6_ENDXSID="SRv6 ENDXSID";
|
public static final String SRv6_ENDXSID="SRv6 ENDXSID";
|
||||||
|
public static final String KLALB_SRv6 = "KLALB_SRv6";
|
||||||
|
|
||||||
private IPv6AddressGroup destination;
|
private IPv6AddressGroup destination;
|
||||||
private IPv6Address nexthop;
|
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,
|
public RouteItem(IPv6AddressGroup destination, IPv6Address nexthop, IPv6NetworkLink destlink, String proto, int pre,
|
||||||
long cost,String flag) {
|
long cost,String flag) {
|
||||||
super();
|
super();
|
||||||
this.destination = destination;
|
this.destination = destination.toNetworkRoute();
|
||||||
this.nexthop = nexthop;
|
this.nexthop = nexthop;
|
||||||
this.destlink = destlink;
|
this.destlink = destlink;
|
||||||
this.proto = proto;
|
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,
|
public RouteItem(IPv6AddressGroup destination, IPv6Address nexthop, IPv6NetworkLink destlink, String proto, int pre,
|
||||||
long cost,Supplier<Long> costSupplier,String flag) {
|
long cost,Supplier<Long> costSupplier,String flag) {
|
||||||
super();
|
super();
|
||||||
this.destination = destination;
|
this.destination = destination.toNetworkRoute();
|
||||||
this.nexthop = nexthop;
|
this.nexthop = nexthop;
|
||||||
this.destlink = destlink;
|
this.destlink = destlink;
|
||||||
this.proto = proto;
|
this.proto = proto;
|
||||||
|
|||||||
@@ -17,14 +17,8 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
@@ -67,7 +61,7 @@ public class KLALBController {
|
|||||||
public HighAccuracyClock getClock() {
|
public HighAccuracyClock getClock() {
|
||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
private final long TIME_WINDOW=2000000000L;
|
private final long TIME_WINDOW=30000000000L;
|
||||||
private SpeedAndTrafficMonitorDataImpl linkMonitor = new SpeedAndTrafficMonitorDataImpl(
|
private SpeedAndTrafficMonitorDataImpl linkMonitor = new SpeedAndTrafficMonitorDataImpl(
|
||||||
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100,TIME_WINDOW ),
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100,TIME_WINDOW ),
|
||||||
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "down", 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 debug=false;
|
||||||
private static final boolean showpacket = 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 final int DISCOVERY_PORT = 4569;
|
||||||
|
|
||||||
private static List<IPMulticastDiscovery> ipmd = new ArrayList<>();
|
private static List<IPMulticastDiscovery> ipmd = new ArrayList<>();
|
||||||
@@ -104,23 +98,9 @@ public class KLALBController {
|
|||||||
public List<InetAddress> getDnsAddresses() {
|
public List<InetAddress> getDnsAddresses() {
|
||||||
return dnsAddresses;
|
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 Runnable tsk1 = new Runnable() {
|
||||||
private TimerTask tsk1 = new TimerTask() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -306,7 +286,7 @@ public class KLALBController {
|
|||||||
return srv6Router.getLocator().getAddress().toInet6Address().equals(inetAddress);
|
return srv6Router.getLocator().getAddress().toInet6Address().equals(inetAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimerTask tsk2 = new TimerTask() {
|
private Runnable tsk2 = new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -634,7 +614,8 @@ public class KLALBController {
|
|||||||
|
|
||||||
private void loadSRv6ProtocolStack(IPv6AddressGroup selfx, boolean enableVirtualAdapter) {
|
private void loadSRv6ProtocolStack(IPv6AddressGroup selfx, boolean enableVirtualAdapter) {
|
||||||
networkInterfaceManager.getInetAddressesExcept().add(selfx.getAddress().toInet6Address());
|
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) {
|
if(configItem!=null) {
|
||||||
srv6Router.setPerformanceStrategy(PerformanceStrategy.fromDescription(configItem.getPerformanceStrategy()));
|
srv6Router.setPerformanceStrategy(PerformanceStrategy.fromDescription(configItem.getPerformanceStrategy()));
|
||||||
srv6Router.setDeviceName(configItem.getDeviceName());
|
srv6Router.setDeviceName(configItem.getDeviceName());
|
||||||
@@ -653,8 +634,7 @@ public class KLALBController {
|
|||||||
if (enableTUN) {
|
if (enableTUN) {
|
||||||
Thread t=new Thread(()->{
|
Thread t=new Thread(()->{
|
||||||
try {
|
try {
|
||||||
IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name.trim(),
|
IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name.trim(),group, SRv6Router.MTU, dnsAddresses);
|
||||||
new IPv6AddressGroup(srv6Router.getLocator().getAddress(), 32), SRv6Router.MTU, dnsAddresses);
|
|
||||||
tunlink.setMonitor(datatMonitor);
|
tunlink.setMonitor(datatMonitor);
|
||||||
// srv6Router.getLinkTabel().add(tunlink);
|
// srv6Router.getLinkTabel().add(tunlink);
|
||||||
srv6Router.getinLoopback().setFallbackLink(tunlink);
|
srv6Router.getinLoopback().setFallbackLink(tunlink);
|
||||||
@@ -686,7 +666,7 @@ public class KLALBController {
|
|||||||
context.syncToSystem();
|
context.syncToSystem();
|
||||||
// System.out.println(context);
|
// System.out.println(context);
|
||||||
try {
|
try {
|
||||||
NTPv4Protocol nvc = new NTPv4Protocol(context,
|
/*NTPv4Protocol nvc = new NTPv4Protocol(context,
|
||||||
new MultiProtocolSocketAddress(iproxyname + "datagram","0.0.0.0",123));
|
new MultiProtocolSocketAddress(iproxyname + "datagram","0.0.0.0",123));
|
||||||
srv6Router.addSRv6RouterListener(new SRv6RouterListener() {
|
srv6Router.addSRv6RouterListener(new SRv6RouterListener() {
|
||||||
|
|
||||||
@@ -718,7 +698,7 @@ public class KLALBController {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
nvc2 = new NTPv4Protocol(context, new MultiProtocolSocketAddress("udp","0.0.0.0",0));
|
nvc2 = new NTPv4Protocol(context, new MultiProtocolSocketAddress("udp","0.0.0.0",0));
|
||||||
|
|
||||||
System.out.println(" Loaded: NTP Module");
|
System.out.println(" Loaded: NTP Module");
|
||||||
@@ -734,8 +714,8 @@ public class KLALBController {
|
|||||||
private void loadController() {
|
private void loadController() {
|
||||||
this.apiServer = new KLALBRoutingProtocolAPIServer(routingProtocol, this);
|
this.apiServer = new KLALBRoutingProtocolAPIServer(routingProtocol, this);
|
||||||
this.apiClient = new KLALBRoutingProtocolAPIClient(routingProtocol);
|
this.apiClient = new KLALBRoutingProtocolAPIClient(routingProtocol);
|
||||||
twk.schedule(tsk1, 5000, 5000);
|
KLALBScheduler.getScheduler().scheduleAtFixedRate(tsk1, 5000, 5000,TimeUnit.MILLISECONDS);
|
||||||
twk.schedule(tsk2, 5000, 5000);
|
KLALBScheduler.getScheduler().scheduleAtFixedRate(tsk2, 5000, 5000,TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KLALBController() {
|
public KLALBController() {
|
||||||
@@ -753,17 +733,12 @@ public class KLALBController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void initKLALB(boolean enableVirtualAdapter, IPv6AddressGroup selfg) {
|
protected void initKLALB(boolean enableVirtualAdapter, IPv6AddressGroup selfg) {
|
||||||
ThreadTool.makeVDaemonThread("线路性能采样线程", ()->{
|
KLALBScheduler.getScheduler().scheduleWithFixedDelay( ()->{
|
||||||
while(true) {
|
|
||||||
linkMonitor.update();
|
linkMonitor.update();
|
||||||
datatMonitor.update();
|
},1,1,TimeUnit.MILLISECONDS);
|
||||||
try {
|
KLALBScheduler.getScheduler().scheduleWithFixedDelay( ()->{
|
||||||
Thread.sleep(1);
|
datatMonitor.update();
|
||||||
} catch (InterruptedException e) {
|
},1,1,TimeUnit.MILLISECONDS);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
loadSRv6ProtocolStack(selfg, enableVirtualAdapter);
|
loadSRv6ProtocolStack(selfg, enableVirtualAdapter);
|
||||||
loadController();
|
loadController();
|
||||||
}
|
}
|
||||||
@@ -804,7 +779,7 @@ public class KLALBController {
|
|||||||
List<MultiProtocolSocketAddress> linele = configItem.getExternalEndpoints();
|
List<MultiProtocolSocketAddress> linele = configItem.getExternalEndpoints();
|
||||||
if (linele != null) {
|
if (linele != null) {
|
||||||
getExternalEndpoints().addAll(linele);
|
getExternalEndpoints().addAll(linele);
|
||||||
}
|
}
|
||||||
List<MultiProtocolSocketAddress> linetoc = configItem.getAutoConnections();
|
List<MultiProtocolSocketAddress> linetoc = configItem.getAutoConnections();
|
||||||
if (linetoc != null) {
|
if (linetoc != null) {
|
||||||
linetoc.forEach((aline) -> {
|
linetoc.forEach((aline) -> {
|
||||||
@@ -856,9 +831,8 @@ public class KLALBController {
|
|||||||
return srv6Router;
|
return srv6Router;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Timer trtr = new Timer("路由表刷新计时器", true);
|
|
||||||
{
|
{
|
||||||
trtr.scheduleAtFixedRate(new TimerTask() {
|
KLALBScheduler.getScheduler().scheduleAtFixedRate(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -869,9 +843,9 @@ public class KLALBController {
|
|||||||
srv6Router.updateRouteTabel();
|
srv6Router.updateRouteTabel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 100, 100);
|
}, 100, 100, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
trtr.scheduleAtFixedRate(new TimerTask() {
|
KLALBScheduler.getScheduler().scheduleAtFixedRate(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
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) {
|
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.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.Condition;
|
import java.util.concurrent.locks.Condition;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.LockSupport;
|
import java.util.concurrent.locks.LockSupport;
|
||||||
import java.util.function.Consumer;
|
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.HighAccuracyClock;
|
||||||
import org.kne.cloud.clock.NTPTimestamps;
|
import org.kne.cloud.clock.NTPTimestamps;
|
||||||
import org.kne.cloud.clock.ReliabilityBackoffTimeClock;
|
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.CongestionAlgorithms;
|
||||||
import org.kne.cloud.network.congestion.DetnetCongestionAlgorithm;
|
import org.kne.cloud.network.congestion.DetnetCongestionAlgorithm;
|
||||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||||
import org.kne.cloud.network.ipv6.ControlledIPv6NetworkLink;
|
import org.kne.cloud.network.ipv6.*;
|
||||||
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.IPv6Packet.IPv6HopByHopHeader;
|
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.CostSupplierFactory;
|
||||||
import org.kne.cloud.network.monitor.DelayMonitorData;
|
import org.kne.cloud.network.monitor.DelayMonitorData;
|
||||||
import org.kne.cloud.network.monitor.LinkStatus;
|
import org.kne.cloud.network.monitor.LinkStatus;
|
||||||
@@ -149,6 +142,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
this.addressGroup = address;
|
this.addressGroup = address;
|
||||||
monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
||||||
name=kpl.toString();
|
name=kpl.toString();
|
||||||
|
setCostSupplier( CostSupplierFactory.owdSupplier(monitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
private KLALBRemoteLink(KLALBController controller, MultiProtocolSocketAddress mpa, MultiProtocolSocketAddress bindaddr, IPv6AddressGroup address) {
|
private KLALBRemoteLink(KLALBController controller, MultiProtocolSocketAddress mpa, MultiProtocolSocketAddress bindaddr, IPv6AddressGroup address) {
|
||||||
@@ -164,6 +158,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
} else {
|
} else {
|
||||||
name=bindaddr.toString() + "→" + mpa.toString();
|
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 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 WatchDogTimer watchdog = new WatchDogTimer(400000000L);
|
||||||
|
|
||||||
private ThreadParker tlock = new ThreadParker();
|
private ThreadParker tlock = new ThreadParker();
|
||||||
@@ -283,12 +278,12 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
sendLock.lock();
|
sendLock.lock();
|
||||||
try {
|
try {
|
||||||
kplink.flush();
|
kplink.flush();
|
||||||
watchdog.feed();
|
|
||||||
}finally {
|
}finally {
|
||||||
sendLock.unlock();
|
sendLock.unlock();
|
||||||
}
|
}
|
||||||
|
watchdog.feed();
|
||||||
}
|
}
|
||||||
tlock.parkNanos(10000000L);
|
tlock.parkNanos(1000000L);
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (StreamCorruptedException sce) {
|
} catch (StreamCorruptedException sce) {
|
||||||
@@ -568,20 +563,17 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
private ThreadParker tpk=new ThreadParker();
|
private ThreadParker tpk=new ThreadParker();
|
||||||
|
|
||||||
private StateManager stateManager;
|
private StateManager stateManager;
|
||||||
private MonitorUpdater monitorUpdater;
|
private ScheduledFuture<?> monitorUpdater;
|
||||||
private class MonitorUpdater implements Runnable{
|
private class MonitorUpdater implements Runnable{
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!closed) {
|
if(closed) {
|
||||||
|
monitorUpdater.cancel(false);
|
||||||
|
}else{
|
||||||
status.updateReliability();
|
status.updateReliability();
|
||||||
if(status.getState()!=LinkStatus.DOWN) {
|
if(status.getState()!=LinkStatus.DOWN) {
|
||||||
monitor.update();
|
monitor.update();
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
Thread.sleep(1);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,8 +745,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
|
|
||||||
protected void startIO() {
|
protected void startIO() {
|
||||||
stateManager=new StateManager();
|
stateManager=new StateManager();
|
||||||
monitorUpdater=new MonitorUpdater();
|
monitorUpdater=KLALBScheduler.getScheduler().scheduleWithFixedDelay(new MonitorUpdater(),1,1, TimeUnit.MILLISECONDS);
|
||||||
ThreadTool.makeVDaemonThread("线路性能采样线程", monitorUpdater).start();
|
|
||||||
ThreadTool.makeVDaemonThread("远程线路状态线程", stateManager).start();
|
ThreadTool.makeVDaemonThread("远程线路状态线程", stateManager).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -896,6 +887,8 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
sendWindow.put(val, pack);
|
sendWindow.put(val, pack);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
}else {
|
||||||
|
System.out.println(hop);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendIPv6PacketToLink(pack, val);
|
sendIPv6PacketToLink(pack, val);
|
||||||
@@ -944,28 +937,6 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
return (!isClosed()) && (status.getState() == LinkStatus.UP) ;
|
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
|
@Override
|
||||||
public void setCongressCondition(Lock lock, Condition condition) {
|
public void setCongressCondition(Lock lock, Condition condition) {
|
||||||
@@ -973,14 +944,32 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
sendWindow.setCongressCondition(lock, condition);
|
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));
|
long deltaxnanos = (long) (postcard.getTimestampDeltaLong() * 1000000000.0 / (1L << 32));
|
||||||
if (deltaxnanos > 0) {
|
Long128 curr= sysclk.getCurrentTimeNanos();
|
||||||
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
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);
|
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.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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.MultiProtocolSocketAddress;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
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.VirtualDatagramSocket;
|
||||||
import org.kne.cloud.network.VirtualDatagramSocketImpl;
|
import org.kne.cloud.network.VirtualDatagramSocketImpl;
|
||||||
import org.pcap4j.core.Inets;
|
|
||||||
|
|
||||||
public class KLALBVirtualDatagramSocket extends VirtualDatagramSocket {
|
public class KLALBVirtualDatagramSocket extends VirtualDatagramSocket {
|
||||||
|
|
||||||
|
|||||||
@@ -118,46 +118,50 @@ public class StreamChannelKLALBPacketLink extends AbstractKLALBPacketLink implem
|
|||||||
return true;
|
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
|
@Override
|
||||||
public void writePacket(ByteBuffer kp) throws IOException {
|
public void writePacket(ByteBuffer kp) throws IOException {
|
||||||
ByteBuffer szeWrite=NetworkPacket.bufferAllocator.allocate(4);
|
// 1. 获取并清空缓存的 4 字节 buffer
|
||||||
szeWrite.limit(4);
|
ByteBuffer szeWrite = SIZE_WRITE_BUFFER.get();
|
||||||
//szeWrite.clear();
|
szeWrite.clear();
|
||||||
|
|
||||||
|
// 2. 写入长度并翻转
|
||||||
szeWrite.putInt(kp.limit());
|
szeWrite.putInt(kp.limit());
|
||||||
szeWrite.flip();
|
szeWrite.flip();
|
||||||
KLALBVirtualSocketChannel obj = null;
|
|
||||||
writableChannel.write(new ByteBuffer[] {szeWrite,kp});
|
|
||||||
checkflush();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 3. 发送
|
||||||
|
writableChannel.write(new ByteBuffer[] {szeWrite, kp});
|
||||||
|
checkflush();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer readPacket() throws IOException {
|
public ByteBuffer readPacket() throws IOException {
|
||||||
|
// 1. 获取并清空缓存的 4 字节 buffer
|
||||||
ByteBuffer szeRead=NetworkPacket.bufferAllocator.allocate(4);
|
ByteBuffer szeRead = SIZE_READ_BUFFER.get();
|
||||||
timeoutTimer=System.nanoTime();
|
|
||||||
timerenabled=true;
|
|
||||||
ByteBuffer kp;
|
|
||||||
szeRead.clear();
|
szeRead.clear();
|
||||||
szeRead.limit(4);
|
szeRead.limit(4);
|
||||||
//szeRead.clear();
|
|
||||||
|
timeoutTimer = System.nanoTime();
|
||||||
|
timerenabled = true;
|
||||||
|
ByteBuffer kp;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
KNEChannels.readFully(readableChannel,szeRead);
|
// 2. 读取长度头
|
||||||
|
KNEChannels.readFully(readableChannel, szeRead);
|
||||||
szeRead.flip();
|
szeRead.flip();
|
||||||
int size=szeRead.getInt(0);
|
int size = szeRead.getInt(0);
|
||||||
kp=NetworkPacket.bufferAllocator.allocate(size);
|
|
||||||
|
// 3. 分配真正的数据区(这里如果是高频,建议后续也可以池化,不过现在是按需大小分配)
|
||||||
|
kp = NetworkPacket.bufferAllocator.allocate(size);
|
||||||
kp.limit(size);
|
kp.limit(size);
|
||||||
KNEChannels.readFully(readableChannel, kp);
|
KNEChannels.readFully(readableChannel, kp);
|
||||||
kp.flip();
|
kp.flip();
|
||||||
return kp;
|
return kp;
|
||||||
}finally {
|
} finally {
|
||||||
timerenabled=false;
|
timerenabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import java.awt.*;
|
|||||||
import java.awt.datatransfer.StringSelection;
|
import java.awt.datatransfer.StringSelection;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Timer;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.TimerTask;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
@@ -16,6 +17,7 @@ import javax.swing.border.LineBorder;
|
|||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
|
import com.sun.management.OperatingSystemMXBean;
|
||||||
import org.jfree.chart.plot.dial.*;
|
import org.jfree.chart.plot.dial.*;
|
||||||
import org.jfree.data.general.DefaultValueDataset;
|
import org.jfree.data.general.DefaultValueDataset;
|
||||||
import org.kne.cloud.clock.HighAccuracyClock;
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
@@ -37,8 +39,7 @@ import org.kne.ui.YScrollPane;
|
|||||||
public class KLALBStateGUI3 extends XFrame {
|
public class KLALBStateGUI3 extends XFrame {
|
||||||
|
|
||||||
// ==================== 定时任务相关 ====================
|
// ==================== 定时任务相关 ====================
|
||||||
private TimerTask tsk, tsk2, tsk3, tsk4, tsk5; // 各种定时任务
|
private ScheduledFuture<?> tsk, tsk2, tsk3, tsk4, tsk5; // 各种定时任务
|
||||||
private Timer t, t2, t3; // 定时器
|
|
||||||
|
|
||||||
// ==================== 系统托盘相关 ====================
|
// ==================== 系统托盘相关 ====================
|
||||||
private SystemTray st; // 系统托盘
|
private SystemTray st; // 系统托盘
|
||||||
@@ -57,7 +58,8 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private DefaultValueDataset backplanePPS;
|
private DefaultValueDataset backplanePPS;
|
||||||
private DefaultValueDataset backplaneECNRate;
|
private DefaultValueDataset backplaneECNRate;
|
||||||
private DefaultValueDataset backplaneLossRate;
|
private DefaultValueDataset backplaneLossRate;
|
||||||
|
private DefaultValueDataset CPUload;
|
||||||
|
private DefaultValueDataset RAMusage;
|
||||||
// ==================== 仪表盘文本标注 ====================
|
// ==================== 仪表盘文本标注 ====================
|
||||||
private DialTextAnnotation upSpeedText; // 上行速度文本标注
|
private DialTextAnnotation upSpeedText; // 上行速度文本标注
|
||||||
private DialTextAnnotation downSpeedText; // 下行速度文本标注
|
private DialTextAnnotation downSpeedText; // 下行速度文本标注
|
||||||
@@ -67,6 +69,8 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private DialTextAnnotation backplanePPSText;
|
private DialTextAnnotation backplanePPSText;
|
||||||
private DialTextAnnotation backplaneECNRateText;
|
private DialTextAnnotation backplaneECNRateText;
|
||||||
private DialTextAnnotation backplaneLossRateText;
|
private DialTextAnnotation backplaneLossRateText;
|
||||||
|
private DialTextAnnotation CPUloadText;
|
||||||
|
private DialTextAnnotation RAMusageText;
|
||||||
|
|
||||||
// ==================== UI组件 ====================
|
// ==================== UI组件 ====================
|
||||||
private YScrollPane ysp, yspc; // 可垂直滚动的面板
|
private YScrollPane ysp, yspc; // 可垂直滚动的面板
|
||||||
@@ -77,7 +81,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private JTextField asnFieldSet; // ASN设置框
|
private JTextField asnFieldSet; // ASN设置框
|
||||||
private JCheckBox enableTUN; // 虚拟网卡启用禁用
|
private JCheckBox enableTUN; // 虚拟网卡启用禁用
|
||||||
private JTextField tunDeviceName; // 虚拟网卡名称设置框
|
private JTextField tunDeviceName; // 虚拟网卡名称设置框
|
||||||
private JTextField webListenSet; // Web API 监听地址设置框
|
private JTextField webListenSet; // Web API 监听地址设置框
|
||||||
private NetworkGraphPanel graph; // 网络图面板
|
private NetworkGraphPanel graph; // 网络图面板
|
||||||
private JTextField textFieldLocate; // 定位地址输入框
|
private JTextField textFieldLocate; // 定位地址输入框
|
||||||
private JTextField asnField2; // ASN显示框
|
private JTextField asnField2; // ASN显示框
|
||||||
@@ -434,6 +438,22 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
backplaneLossRateText = lossRate1.getTextAnnotation();
|
backplaneLossRateText = lossRate1.getTextAnnotation();
|
||||||
|
|
||||||
dashs.add(lossRate1);
|
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) {
|
private void initTimers(KLALBController kc) {
|
||||||
t3 = new Timer("监视器刷新线程", true);
|
|
||||||
t2 = new Timer("仪表盘刷新线程", true);
|
|
||||||
t = new Timer("状态刷新线程", true);
|
|
||||||
|
|
||||||
// 创建刷新任务
|
// 创建刷新任务
|
||||||
createRefreshTask(kc, ysp);
|
createRefreshTask(kc, ysp);
|
||||||
}
|
}
|
||||||
@@ -924,10 +940,10 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
webApiEnabled=webApic.getCheckBox();
|
webApiEnabled=webApic.getCheckBox();
|
||||||
settings.getView().add(webApic);
|
settings.getView().add(webApic);
|
||||||
|
|
||||||
TextSettingItem webListen = new TextSettingItem(UIEnv.getRsb().getString("weblistenaddr"),
|
TextSettingItem webListen = new TextSettingItem(UIEnv.getRsb().getString("weblistenaddr"),
|
||||||
CONST.itemwidth, CONST.settingheight);
|
CONST.itemwidth, CONST.settingheight);
|
||||||
webListenSet = webListen.getTextField();
|
webListenSet = webListen.getTextField();
|
||||||
settings.getView().add(webListen);
|
settings.getView().add(webListen);
|
||||||
|
|
||||||
//性能设置标题
|
//性能设置标题
|
||||||
|
|
||||||
@@ -1167,19 +1183,19 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
kck.setTUNName(tunNameText);
|
kck.setTUNName(tunNameText);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存Web API设置
|
// 保存Web API设置
|
||||||
kck.setWebUI(webApiEnabled.isSelected());
|
kck.setWebUI(webApiEnabled.isSelected());
|
||||||
String webListenText = webListenSet.getText().trim();
|
String webListenText = webListenSet.getText().trim();
|
||||||
if (webListenText.equals("")) {
|
if (webListenText.equals("")) {
|
||||||
kck.setWebListen(new MultiProtocolSocketAddress("http", "0.0.0.0", 4665));
|
kck.setWebListen(new MultiProtocolSocketAddress("http", "0.0.0.0", 4665));
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
kck.setWebListen(new MultiProtocolSocketAddress(webListenText));
|
kck.setWebListen(new MultiProtocolSocketAddress(webListenText));
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildweblistenaddr"),
|
JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildweblistenaddr"),
|
||||||
UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
|
UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1322,9 +1338,9 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private void createRefreshTask(KLALBController kc, YScrollPane ysp) {
|
private void createRefreshTask(KLALBController kc, YScrollPane ysp) {
|
||||||
// 线路状态刷新任务
|
// 线路状态刷新任务
|
||||||
if (tsk != null) {
|
if (tsk != null) {
|
||||||
tsk.cancel();
|
tsk.cancel(false);
|
||||||
}
|
}
|
||||||
tsk = new TimerTask() {
|
tsk =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
@@ -1382,28 +1398,27 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
ysp.updateScrool();
|
ysp.updateScrool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 1000, 1000, TimeUnit.MILLISECONDS);
|
||||||
t.scheduleAtFixedRate(tsk, 1000, 1000);
|
|
||||||
|
|
||||||
// 仪表盘数据刷新任务
|
// 仪表盘数据刷新任务
|
||||||
if (tsk2 != null) {
|
if (tsk2 != null) {
|
||||||
tsk2.cancel();
|
tsk2.cancel(false);
|
||||||
}
|
}
|
||||||
tsk2 = new TimerTask() {
|
tsk2 =KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
updateDashboardData(kc);
|
updateDashboardData(kc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 100, 100,TimeUnit.MILLISECONDS);
|
||||||
t2.scheduleAtFixedRate(tsk2, 100, 100);
|
|
||||||
|
|
||||||
// 网络图刷新任务
|
// 网络图刷新任务
|
||||||
if (tsk5 != null) {
|
if (tsk5 != null) {
|
||||||
tsk5.cancel();
|
tsk5.cancel(false);
|
||||||
}
|
}
|
||||||
tsk5 = new TimerTask() {
|
tsk5 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
@@ -1415,8 +1430,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
graph.revalidate();
|
graph.revalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 1000, 1000,TimeUnit.MILLISECONDS);
|
||||||
t.scheduleAtFixedRate(tsk5, 1000, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1425,29 +1439,29 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private void updateDashboardData(KLALBController kc) {
|
private void updateDashboardData(KLALBController kc) {
|
||||||
// 更新上行速度
|
// 更新上行速度
|
||||||
double outload = kc.getLinkMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax();
|
double outload = kc.getLinkMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax();
|
||||||
|
upSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getOutSpeed()) + "/s");
|
||||||
if (Double.isFinite(outload)) {
|
if (Double.isFinite(outload)) {
|
||||||
upSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getOutSpeed()) + "/s");
|
|
||||||
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新下行速度
|
// 更新下行速度
|
||||||
double inload = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax();
|
double inload = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax();
|
||||||
|
downSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getInSpeed()) + "/s");
|
||||||
if (Double.isFinite(inload)) {
|
if (Double.isFinite(inload)) {
|
||||||
downSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getInSpeed()) + "/s");
|
|
||||||
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新上行包速率
|
// 更新上行包速率
|
||||||
double outPPSload = kc.getLinkMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax();
|
double outPPSload = kc.getLinkMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax();
|
||||||
|
upPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getOutPPS()) + "PPS");
|
||||||
if (Double.isFinite(outPPSload)) {
|
if (Double.isFinite(outPPSload)) {
|
||||||
upPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getOutPPS()) + "PPS");
|
|
||||||
upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
|
upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新下行包速率
|
// 更新下行包速率
|
||||||
double inPPSload = kc.getLinkMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax();
|
double inPPSload = kc.getLinkMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax();
|
||||||
|
downPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getInPPS()) + "PPS");
|
||||||
if (Double.isFinite(inPPSload)) {
|
if (Double.isFinite(inPPSload)) {
|
||||||
downPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getInPPS()) + "PPS");
|
|
||||||
downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
|
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) {
|
if(router!=null) {
|
||||||
// 更新背板延迟
|
// 更新背板延迟
|
||||||
double backplaneTimev = router.getBackplaneTime()* 100.0/100000.0;
|
double backplaneTimev = router.getBackplaneTime()* 100.0/100000.0;
|
||||||
|
backplaneDelayText.setLabel(KLALBUtils.convertUintNanoDefalut(router.getBackplaneTime()) + "s");
|
||||||
if (Double.isFinite(backplaneTimev)) {
|
if (Double.isFinite(backplaneTimev)) {
|
||||||
backplaneDelayText.setLabel(KLALBUtils.convertUintNanoDefalut(router.getBackplaneTime()) + "s");
|
|
||||||
backplaneDelay.setValue(Math.min(backplaneDelay.getValue().doubleValue() * 0.98 + backplaneTimev * 0.02, 101.0));
|
backplaneDelay.setValue(Math.min(backplaneDelay.getValue().doubleValue() * 0.98 + backplaneTimev * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新背板转发率
|
// 更新背板转发率
|
||||||
double backplanePPSv = router.getBackplanePPS() * 100.0 / router.getBackplanePPSMax();
|
double backplanePPSv = router.getBackplanePPS() * 100.0 / router.getBackplanePPSMax();
|
||||||
|
backplanePPSText.setLabel(KLALBUtils.convertUintDefalut(router.getBackplanePPS()) + "PPS");
|
||||||
if (Double.isFinite(backplanePPSv)) {
|
if (Double.isFinite(backplanePPSv)) {
|
||||||
backplanePPSText.setLabel(KLALBUtils.convertUintDefalut(router.getBackplanePPS()) + "PPS");
|
|
||||||
backplanePPS.setValue(Math.min(backplanePPS.getValue().doubleValue() * 0.98 + backplanePPSv * 0.02, 101.0));
|
backplanePPS.setValue(Math.min(backplanePPS.getValue().doubleValue() * 0.98 + backplanePPSv * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新背板ECN率
|
// 更新背板ECN率
|
||||||
double backplaneECNv = router.getECNRate() * 100.0 ;
|
double backplaneECNv = router.getECNRate() * 100.0 ;
|
||||||
|
backplaneECNRateText.setLabel(String.format("%.1f",backplaneECNv) + "%");
|
||||||
if (Double.isFinite(backplaneECNv)) {
|
if (Double.isFinite(backplaneECNv)) {
|
||||||
backplaneECNRateText.setLabel(String.format("%.1f",backplaneECNv) + "%");
|
|
||||||
backplaneECNRate.setValue(Math.min(backplaneECNRate.getValue().doubleValue() * 0.98 + backplaneECNv * 0.02, 101.0));
|
backplaneECNRate.setValue(Math.min(backplaneECNRate.getValue().doubleValue() * 0.98 + backplaneECNv * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新背板ECN率
|
// 更新背板ECN率
|
||||||
double backplaneLossv = router.getLossRate() * 100.0 ;
|
double backplaneLossv = router.getLossRate() * 100.0 ;
|
||||||
|
backplaneLossRateText.setLabel(String.format("%.1f",backplaneLossv) + "%");
|
||||||
if (Double.isFinite(backplaneLossv)) {
|
if (Double.isFinite(backplaneLossv)) {
|
||||||
backplaneLossRateText.setLabel(String.format("%.1f",backplaneLossv) + "%");
|
|
||||||
backplaneLossRate.setValue(Math.min(backplaneLossRate.getValue().doubleValue() * 0.98 + backplaneLossv * 0.02, 101.0));
|
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());
|
String contt = Long.toString(kc.getIpv6Router().getKlalbRouteProtol().getDevicesFound());
|
||||||
if (!contt.equals(devicesOnline.getText())) {
|
if (!contt.equals(devicesOnline.getText())) {
|
||||||
@@ -1588,10 +1623,10 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 加载Web API设置
|
// 加载Web API设置
|
||||||
webApiEnabled.setSelected(kck.isWebUI());
|
webApiEnabled.setSelected(kck.isWebUI());
|
||||||
webListenSet.setText(kck.getWebListen() != null ? kck.getWebListen().toString()
|
webListenSet.setText(kck.getWebListen() != null ? kck.getWebListen().toString()
|
||||||
: "http://0.0.0.0:4665");
|
: "http://0.0.0.0:4665");
|
||||||
|
|
||||||
// 加载TCP监听
|
// 加载TCP监听
|
||||||
MultiProtocolSocketAddress mpat = kck.getTCPListen();
|
MultiProtocolSocketAddress mpat = kck.getTCPListen();
|
||||||
@@ -1764,7 +1799,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
public void close() {
|
public void close() {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
if (tsk != null) {
|
if (tsk != null) {
|
||||||
tsk.cancel();
|
tsk.cancel(false);
|
||||||
}
|
}
|
||||||
if (st != null) {
|
if (st != null) {
|
||||||
st.remove(ti);
|
st.remove(ti);
|
||||||
@@ -1779,4 +1814,4 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
KLALBStateGUI3 kcg = new KLALBStateGUI3(new KLALBController());
|
KLALBStateGUI3 kcg = new KLALBStateGUI3(new KLALBController());
|
||||||
kcg.setVisible(true);
|
kcg.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.jfree.chart.plot.dial.DialTextAnnotation;
|
|||||||
import org.jfree.data.general.DefaultValueDataset;
|
import org.jfree.data.general.DefaultValueDataset;
|
||||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||||
import org.kne.cloud.network.klalb.CONST;
|
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.klalb.KLALBUtils;
|
||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||||
import org.kne.cloud.network.perf.Kperf;
|
import org.kne.cloud.network.perf.Kperf;
|
||||||
@@ -35,17 +36,17 @@ import java.awt.event.ActionEvent;
|
|||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
public class KperfGUI extends XFrame{
|
public class KperfGUI extends XFrame{
|
||||||
private static Timer tmr=new Timer();
|
|
||||||
|
|
||||||
private KperfReports reports=new KperfReportsImpl();
|
private KperfReports reports=new KperfReportsImpl();
|
||||||
private Kperf kperf;
|
private Kperf kperf;
|
||||||
private JTextField targetAddressField;
|
private JTextField targetAddressField;
|
||||||
private JButton startButton;
|
private JButton startButton;
|
||||||
private JProgressBar progressBar;
|
|
||||||
private DefaultValueDataset upSpeed;
|
private DefaultValueDataset upSpeed;
|
||||||
private DefaultValueDataset upDataSpeed;
|
private DefaultValueDataset upDataSpeed;
|
||||||
private DialTextAnnotation upSpeedText;
|
private DialTextAnnotation upSpeedText;
|
||||||
@@ -54,7 +55,7 @@ public class KperfGUI extends XFrame{
|
|||||||
private DialTextAnnotation downSpeedText;
|
private DialTextAnnotation downSpeedText;
|
||||||
private JTextField sourceAddressField;
|
private JTextField sourceAddressField;
|
||||||
|
|
||||||
private SpeedAndTrafficAndDelayMonitorDataImpl monitor;
|
private volatile SpeedAndTrafficAndDelayMonitorDataImpl monitor;
|
||||||
|
|
||||||
private DefaultValueDataset upPPS;
|
private DefaultValueDataset upPPS;
|
||||||
|
|
||||||
@@ -68,12 +69,8 @@ public class KperfGUI extends XFrame{
|
|||||||
|
|
||||||
private DialTextAnnotation downPPSText;
|
private DialTextAnnotation downPPSText;
|
||||||
|
|
||||||
private TimerTask tsk;
|
private ScheduledFuture<?> tsk;
|
||||||
private class KperfReportsImpl implements KperfReports{
|
private class KperfReportsImpl implements KperfReports{
|
||||||
@Override
|
|
||||||
public void testProcess(double process) {
|
|
||||||
progressBar.setValue((int) (process*100.0f));
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public void testFinish() {
|
public void testFinish() {
|
||||||
if(kperf!=null) {
|
if(kperf!=null) {
|
||||||
@@ -216,254 +213,12 @@ public class KperfGUI extends XFrame{
|
|||||||
panel_6.add(downPPSLabel, BorderLayout.EAST);
|
panel_6.add(downPPSLabel, BorderLayout.EAST);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
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);
|
upSpeed = new DefaultValueDataset(0);
|
||||||
upDataSpeed = 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);
|
dialup.addGradientRanges(UIEnv.RANGE_1);
|
||||||
upSpeedText =dialup.getTextAnnotation();
|
upSpeedText =dialup.getTextAnnotation();
|
||||||
|
|
||||||
@@ -474,7 +229,7 @@ public class KperfGUI extends XFrame{
|
|||||||
// 下行速度仪表盘
|
// 下行速度仪表盘
|
||||||
downSpeed = new DefaultValueDataset(0);
|
downSpeed = new DefaultValueDataset(0);
|
||||||
downDataSpeed = 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);
|
dialdown.addGradientRanges(UIEnv.RANGE_1);
|
||||||
downSpeedText =dialdown.getTextAnnotation();
|
downSpeedText =dialdown.getTextAnnotation();
|
||||||
|
|
||||||
@@ -484,7 +239,7 @@ public class KperfGUI extends XFrame{
|
|||||||
// 上行包速率仪表盘
|
// 上行包速率仪表盘
|
||||||
upPPS = new DefaultValueDataset(0);
|
upPPS = new DefaultValueDataset(0);
|
||||||
upDataPPS = 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);
|
dialupPPS.addGradientRanges(UIEnv.RANGE_1);
|
||||||
upPPSText = dialupPPS.getTextAnnotation();
|
upPPSText = dialupPPS.getTextAnnotation();
|
||||||
|
|
||||||
@@ -493,7 +248,7 @@ public class KperfGUI extends XFrame{
|
|||||||
// 下行包速率仪表盘
|
// 下行包速率仪表盘
|
||||||
downPPS = new DefaultValueDataset(0);
|
downPPS = new DefaultValueDataset(0);
|
||||||
downDataPPS = 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);
|
dialdownPPS.addGradientRanges(UIEnv.RANGE_1);
|
||||||
downPPSText = dialdownPPS.getTextAnnotation();
|
downPPSText = dialdownPPS.getTextAnnotation();
|
||||||
|
|
||||||
@@ -520,10 +275,7 @@ public class KperfGUI extends XFrame{
|
|||||||
panel_top.add(panel);
|
panel_top.add(panel);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
progressBar = new JProgressBar();
|
|
||||||
progressBar.setPreferredSize(new Dimension(100, 5));
|
|
||||||
getContentPane().add(progressBar, BorderLayout.NORTH);
|
|
||||||
getTitlelabel().setFont(UIEnv.getFont().deriveFont(17.0f));
|
getTitlelabel().setFont(UIEnv.getFont().deriveFont(17.0f));
|
||||||
getTitlepanel().setBorder(new LineBorder(Color.LIGHT_GRAY));
|
getTitlepanel().setBorder(new LineBorder(Color.LIGHT_GRAY));
|
||||||
getTitlelabel().setForeground(Color.WHITE);
|
getTitlelabel().setForeground(Color.WHITE);
|
||||||
@@ -532,38 +284,37 @@ public class KperfGUI extends XFrame{
|
|||||||
setSize(CONST.windowwidth,CONST.windowheight );
|
setSize(CONST.windowwidth,CONST.windowheight );
|
||||||
setResizable(false);
|
setResizable(false);
|
||||||
setLocationRelativeTo(comp);
|
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");
|
|
||||||
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
double inload = monitor.getInSpeed() * 100.0 / monitor.getInSpeedMax();
|
@Override
|
||||||
if (Double.isFinite(inload)) {
|
public void run() {
|
||||||
downSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getInSpeed()) + "/s");
|
if(monitor!=null) {
|
||||||
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
double outload = monitor.getOutSpeed() * 100.0 / monitor.getOutSpeedMax();
|
||||||
}
|
upSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getOutSpeed()) + "/s");
|
||||||
|
if (Double.isFinite(outload)) {
|
||||||
double outPPSload = monitor.getOutPPS() * 100.0 / monitor.getOutPPSMax();
|
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
||||||
if (Double.isFinite(outPPSload)) {
|
|
||||||
upPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getOutPPS()) + "PPS");
|
|
||||||
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");
|
|
||||||
downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
tmr.scheduleAtFixedRate(tsk, 200, 100);
|
double inload = monitor.getInSpeed() * 100.0 / monitor.getInSpeedMax();
|
||||||
|
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();
|
||||||
|
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();
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 200, 100, TimeUnit.MILLISECONDS);
|
||||||
addWindowListener(new WindowListener() {
|
addWindowListener(new WindowListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -593,7 +344,7 @@ public class KperfGUI extends XFrame{
|
|||||||
@Override
|
@Override
|
||||||
public void windowClosing(WindowEvent e) {
|
public void windowClosing(WindowEvent e) {
|
||||||
if(tsk!=null)
|
if(tsk!=null)
|
||||||
tsk.cancel();
|
tsk.cancel(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.GridLayout;
|
import java.awt.GridLayout;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Timer;
|
import java.util.Scanner;
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@@ -18,11 +17,15 @@ import org.jfree.chart.JFreeChart;
|
|||||||
import org.jfree.data.time.Millisecond;
|
import org.jfree.data.time.Millisecond;
|
||||||
import org.jfree.data.time.TimeSeries;
|
import org.jfree.data.time.TimeSeries;
|
||||||
import org.jfree.data.time.TimeSeriesCollection;
|
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.SendPacketSlidingWindow;
|
||||||
|
import org.kne.cloud.network.congestion.Vegas2CongestionAlgorithm;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||||
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
import org.kne.cloud.network.klalb.KLALBRemoteLink;
|
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.LinkStatus;
|
||||||
import org.kne.cloud.network.monitor.TimestampMonitorValue;
|
import org.kne.cloud.network.monitor.TimestampMonitorValue;
|
||||||
import org.kne.math.Long128;
|
import org.kne.math.Long128;
|
||||||
@@ -35,19 +38,18 @@ import javax.swing.ImageIcon;
|
|||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.awt.event.WindowListener;
|
import java.awt.event.WindowListener;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.swing.JSlider;
|
import javax.swing.JSlider;
|
||||||
|
|
||||||
public class LineMonitorGUI extends XFrame {
|
public class LineMonitorGUI extends XFrame {
|
||||||
private Timer timer;
|
private ScheduledFuture<?> tsk3;
|
||||||
private Timer timer1;
|
|
||||||
private Timer timer2;
|
|
||||||
private Timer timer3;
|
|
||||||
private TimerTask tsk3;
|
|
||||||
|
|
||||||
private TimerTask tsk4, tsk5,tsk6;
|
private ScheduledFuture<?> tsk4, tsk5,tsk6,tsk7;
|
||||||
private TimerTask d1;
|
private ScheduledFuture<?> d1;
|
||||||
private TimerTask d2;
|
private ScheduledFuture<?> d2;
|
||||||
private TimerTask d3;
|
private ScheduledFuture<?> d3;
|
||||||
|
private ScheduledFuture<?> d4;
|
||||||
|
|
||||||
private TimeSeries spdup = new TimeSeries(UIEnv.getRsb().getString("uploadspeed"));
|
private TimeSeries spdup = new TimeSeries(UIEnv.getRsb().getString("uploadspeed"));
|
||||||
private TimeSeries spddown = new TimeSeries(UIEnv.getRsb().getString("downloadspeed"));
|
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 queueused = new TimeSeries(UIEnv.getRsb().getString("queueused"));
|
||||||
private TimeSeries buffermax = new TimeSeries(UIEnv.getRsb().getString("maxbuffer"));
|
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 KLALBRemoteLink tr;
|
||||||
private JFreeChart jfc;
|
private JFreeChart jfc;
|
||||||
private JFreeChart jfce;
|
private JFreeChart jfce;
|
||||||
private JFreeChart jbfc;
|
private JFreeChart jbfc;
|
||||||
|
private JFreeChart jbfcv;
|
||||||
private JLabel spdp;
|
private JLabel spdp;
|
||||||
private JLabel delp;
|
private JLabel delp;
|
||||||
private JLabel sbpdp;
|
private JLabel sbpdp;
|
||||||
|
private JLabel sbpdpv;
|
||||||
private long timeRange = 5000;
|
private long timeRange = 5000;
|
||||||
private long[] values = new long[] { 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000 };
|
private long[] values = new long[] { 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000 };
|
||||||
private JPanel panel_1;
|
private JPanel panel_1;
|
||||||
@@ -155,6 +166,24 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
jp.add(sbpdp);
|
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);
|
buffermax.setMaximumItemCount((int) timeRange/5);
|
||||||
queueused.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");
|
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
|
@Override
|
||||||
public void setVisible(boolean b) {
|
public void setVisible(boolean b) {
|
||||||
if (b) {
|
if (b) {
|
||||||
if (timer == null) {
|
if (tsk3 == null) {
|
||||||
timer = new Timer();
|
|
||||||
timer1 = new Timer();
|
tsk3 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
timer2 = new Timer();
|
|
||||||
timer3 = new Timer();
|
|
||||||
tsk3 = new TimerTask() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
updateTraffic();
|
updateTraffic();
|
||||||
}
|
}
|
||||||
};
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
tsk4 = new TimerTask() {
|
tsk4 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
recordSpeedData();
|
recordSpeedData();
|
||||||
}
|
}
|
||||||
};
|
}, 10, 10, TimeUnit.MILLISECONDS);;
|
||||||
|
|
||||||
tsk5 = new TimerTask() {
|
tsk5 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
recordDelayData();
|
recordDelayData();
|
||||||
}
|
}
|
||||||
};
|
}, 10, 10, TimeUnit.MILLISECONDS);
|
||||||
tsk6 = new TimerTask() {
|
tsk6 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
recordBufferData();
|
recordBufferData();
|
||||||
}
|
}
|
||||||
};
|
}, 10, 10, TimeUnit.MILLISECONDS);
|
||||||
d1 = new TimerTask() {
|
tsk7 = KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
recordCongestionData();
|
||||||
|
}
|
||||||
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
|
d1 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -377,8 +440,8 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
} ,25, 25, TimeUnit.MILLISECONDS);
|
||||||
d2 = new TimerTask() {
|
d2 = KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -391,8 +454,8 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
d3 = new TimerTask() {
|
d3 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -405,40 +468,46 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
timer.scheduleAtFixedRate(tsk3, 25, 25);
|
d4 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
timer1.scheduleAtFixedRate(tsk4, 10, 10);
|
|
||||||
timer1.scheduleAtFixedRate(d1, 25, 25);
|
@Override
|
||||||
timer2.scheduleAtFixedRate(tsk5, 10, 10);
|
public void run() {
|
||||||
timer2.scheduleAtFixedRate(d2, 25, 25);
|
if (isVisible()) {
|
||||||
timer3.scheduleAtFixedRate(tsk6, 10, 10);
|
synchronized (jbfcv) {
|
||||||
timer3.scheduleAtFixedRate(d3, 25, 25);
|
ImageIcon i3 = new ImageIcon(
|
||||||
|
jbfcv.createBufferedImage(sbpdpv.getWidth(), sbpdpv.getHeight()));
|
||||||
|
sbpdpv.setIcon(i3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (tsk3 != null)
|
if (tsk3 != null)
|
||||||
tsk3.cancel();
|
tsk3.cancel(false);
|
||||||
if (tsk4 != null)
|
if (tsk4 != null)
|
||||||
tsk4.cancel();
|
tsk4.cancel(false);
|
||||||
if (tsk5 != null)
|
if (tsk5 != null)
|
||||||
tsk5.cancel();
|
tsk5.cancel(false);
|
||||||
|
if (tsk6 != null)
|
||||||
|
tsk6.cancel(false);
|
||||||
|
if (tsk7 != null)
|
||||||
|
tsk7.cancel(false);
|
||||||
if (d1 != null)
|
if (d1 != null)
|
||||||
d1.cancel();
|
d1.cancel(false);
|
||||||
if (d2 != null)
|
if (d2 != null)
|
||||||
d2.cancel();
|
d2.cancel(false);
|
||||||
if (d3 != null)
|
if (d3 != null)
|
||||||
d3.cancel();
|
d3.cancel(false);
|
||||||
if (timer != null)
|
if (d4 != null)
|
||||||
timer.cancel();
|
d4.cancel(false);
|
||||||
if (timer1 != null)
|
tsk3=null;
|
||||||
timer1.cancel();
|
|
||||||
|
|
||||||
if (timer2 != null)
|
|
||||||
timer2.cancel();
|
|
||||||
|
|
||||||
if (timer3 != null)
|
|
||||||
timer3.cancel();
|
|
||||||
timer = null;
|
|
||||||
}
|
}
|
||||||
super.setVisible(b);
|
super.setVisible(b);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,20 +3,18 @@ package org.kne.cloud.network.kltp;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.BindException;
|
import java.net.BindException;
|
||||||
import java.net.Inet6Address;
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.WritableByteChannel;
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||||
import org.kne.concurrent.*;
|
import org.kne.concurrent.*;
|
||||||
import org.kne.cloud.network.NetworkPacket;
|
|
||||||
import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
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.DCTCPCongestionAlgorithm;
|
||||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
import org.kne.cloud.network.klalb.DATATPacket;
|
|
||||||
import org.kne.cloud.network.klalb.KLALBController;
|
import org.kne.cloud.network.klalb.KLALBController;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -238,23 +236,27 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if(sendMap.isClosed())
|
if(sendMap.isClosed()) {
|
||||||
tt.cancel(false);
|
tt.cancel(false);
|
||||||
try {
|
}else if(!sendMap.isCongestion()){
|
||||||
if(olock!=null)
|
|
||||||
olock.lock();
|
|
||||||
try {
|
try {
|
||||||
flush0();
|
if (olock != null)
|
||||||
}finally {
|
olock.lock();
|
||||||
if(olock!=null)
|
try {
|
||||||
olock.unlock();
|
if(!sendMap.isCongestion()) {
|
||||||
|
flush0();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (olock != null)
|
||||||
|
olock.unlock();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
ioe.set(e);
|
||||||
}
|
}
|
||||||
} 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();
|
IOException ioex=ioe.get();
|
||||||
@@ -271,7 +273,7 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
|||||||
|
|
||||||
sendMap.waitForAvaliable();
|
sendMap.waitForAvaliable();
|
||||||
|
|
||||||
controller.getIpv6Router().runPacketSendTask(()->{
|
controller.getIpv6Router().enqueuePacketSendTask(()->{
|
||||||
pack.getKLTPData().flip();
|
pack.getKLTPData().flip();
|
||||||
pack.incSendCounter();
|
pack.incSendCounter();
|
||||||
sendMap.put(pack.getSequence(),pack);
|
sendMap.put(pack.getSequence(),pack);
|
||||||
@@ -353,7 +355,7 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
|||||||
KLTPPacket kltp=(KLTPPacket) u.getPayload();
|
KLTPPacket kltp=(KLTPPacket) u.getPayload();
|
||||||
switch(kltp.getType()) {
|
switch(kltp.getType()) {
|
||||||
case KLTPPacket.KLTP_TYPE_ACK:
|
case KLTPPacket.KLTP_TYPE_ACK:
|
||||||
sendMap.ack(kltp.getSequence(), kltp.isCE());
|
sendMap.ack(kltp.getSequence(),0, kltp.isCE());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
|||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ArrayListTimestampMonitor(HighAccuracyClock clock, String name, int maxRetry, long cleanupThreshold) {
|
public ArrayListTimestampMonitor(HighAccuracyClock clock, String name, int maxRetry, long cleanupThreshold) {
|
||||||
super();
|
super();
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -66,7 +66,12 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
|||||||
public boolean recordPacket(K key,int count, int length) {
|
public boolean recordPacket(K key,int count, int length) {
|
||||||
return recordPacket(key,clock.getCurrentTimeNanos(),count,length);
|
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) {
|
public boolean recordPacket(K key,int count, int length, long delay) {
|
||||||
return recordPacket(key, clock.getCurrentTimeNanos(),count, length, 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);
|
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);
|
validateTimestamp(timestamp);
|
||||||
|
|
||||||
// 快速路径:尝试sequence=0
|
// 快速路径:尝试sequence=0
|
||||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 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);
|
autoCleanup(cleanupThreshold);
|
||||||
|
|
||||||
rwLock.writeLock().lock();
|
rwLock.writeLock().lock();
|
||||||
@@ -460,7 +470,49 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
|||||||
return Long.MAX_VALUE / 1024;
|
return Long.MAX_VALUE / 1024;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从已排序的列表中计算数据量 - 优化版本,只需要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;
|
private volatile TimestampMonitorValue recent=null;
|
||||||
@Override
|
@Override
|
||||||
public TimestampMonitorValue getRecentDelayEntry() {
|
public TimestampMonitorValue getRecentDelayEntry() {
|
||||||
|
|||||||
@@ -75,16 +75,23 @@ private String name;
|
|||||||
public boolean recordPacket(K key,int count, int length, long delay) {
|
public boolean recordPacket(K key,int count, int length, long delay) {
|
||||||
return recordPacket(key,clock.getCurrentTimeNanos(),count,length,delay);
|
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);
|
autoCleanup(cleanupThreshold);
|
||||||
// 快速路径:尝试sequence=0
|
// 快速路径:尝试sequence=0
|
||||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 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) {
|
if (entries.putIfAbsent(monitorKey, monitorValue) == null) {
|
||||||
totalDataSize.add(length);
|
totalDataSize.add(length);
|
||||||
@@ -304,7 +311,18 @@ private String name;
|
|||||||
// TODO 自动生成的方法存根
|
// TODO 自动生成的方法存根
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
|
@Override
|
||||||
|
public long calculateMinDelay(long timeWindowNs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long calculateMinDelay(Long128 currentTime, long timeWindowNs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TimestampMonitorValue getRecentDelayEntry() {
|
public TimestampMonitorValue getRecentDelayEntry() {
|
||||||
// TODO 自动生成的方法存根
|
// TODO 自动生成的方法存根
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -19,27 +19,17 @@ public class SpeedAndTrafficAndDelayMonitorDataImpl extends SpeedAndTrafficMonit
|
|||||||
upSampler.update();
|
upSampler.update();
|
||||||
downSampler.update();
|
downSampler.update();
|
||||||
if(upSampler.getSnapshotPacketCount()>0&&upSampler.getSnapshotTotalDelay()>0) {
|
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) {
|
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();
|
long time=System.nanoTime();
|
||||||
if(time-stime>timewindowmax) {
|
if(time-stime>timewindowmax) {
|
||||||
|
outDelayMin=getUploadBandwidth().calculateMinDelay(super.getTimeWindowMax());
|
||||||
|
inDelayMin=getDownloadBandwidth().calculateMinDelay(super.getTimeWindowMax());
|
||||||
stime=time;
|
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>uploadBandwidth;
|
||||||
private TimestampMonitor<UUID>downloadBandwidth;
|
private TimestampMonitor<UUID>downloadBandwidth;
|
||||||
private long timewindow=1000000000L;
|
private long timewindow=1000000000L;
|
||||||
private long timewindowmax=1000000000L;
|
private long timewindowmax=30000000000L;
|
||||||
private BandwidthSampler upSampler=new BandwidthSampler();
|
private BandwidthSampler upSampler=new BandwidthSampler();
|
||||||
private BandwidthSampler downSampler=new BandwidthSampler();
|
private BandwidthSampler downSampler=new BandwidthSampler();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private final long TIME_WINDOW=2000000000L;
|
private final long TIME_WINDOW=50000000000L;
|
||||||
public SpeedAndTrafficMonitorDataImpl(HighAccuracyClock clock) {
|
public SpeedAndTrafficMonitorDataImpl(HighAccuracyClock clock) {
|
||||||
super();
|
super();
|
||||||
this.clock=clock;
|
this.clock=clock;
|
||||||
@@ -177,32 +177,39 @@ public class SpeedAndTrafficMonitorDataImpl extends MonitorDataImpl implements S
|
|||||||
inPPSEvaluator.markDirty();
|
inPPSEvaluator.markDirty();
|
||||||
}
|
}
|
||||||
long time=System.nanoTime();
|
long time=System.nanoTime();
|
||||||
if(time-stime>timewindowmax) {
|
if(time-stime>timewindow) {
|
||||||
stime=time;
|
stime=time;
|
||||||
long os=uploadBandwidth.calculateBandwidth(timewindowmax);
|
long os=uploadBandwidth.calculateBandwidth(timewindowmax);
|
||||||
long is=downloadBandwidth.calculateBandwidth(timewindowmax);
|
long is=downloadBandwidth.calculateBandwidth(timewindowmax);
|
||||||
long op=uploadBandwidth.calculatePacketRate(timewindowmax);
|
long op=uploadBandwidth.calculatePacketRate(timewindowmax);
|
||||||
long ip=uploadBandwidth.calculatePacketRate(timewindowmax);
|
long ip=uploadBandwidth.calculatePacketRate(timewindowmax);
|
||||||
if(os>outSpeeedMax) {
|
if(os>outSpeeedMax) {
|
||||||
outSpeeedMax=(outSpeeedMax+os)/2;
|
outSpeeedMax=os;
|
||||||
}else {
|
}else {
|
||||||
outSpeeedMax=(outSpeeedMax*999+os)/1000;
|
outSpeeedMax=(outSpeeedMax*999+os)/1000;
|
||||||
}
|
}
|
||||||
if(is>inSpeedMax) {
|
if(is>inSpeedMax) {
|
||||||
inSpeedMax=(inSpeedMax+is)/2;
|
inSpeedMax=is;
|
||||||
}else {
|
}else {
|
||||||
inSpeedMax=(inSpeedMax*999+is)/1000;
|
inSpeedMax=(inSpeedMax*999+is)/1000;
|
||||||
}
|
}
|
||||||
if(op>outPPSMax) {
|
if(op>outPPSMax) {
|
||||||
outPPSMax=(outPPSMax+op)/2;
|
outPPSMax=op;
|
||||||
}else {
|
}else {
|
||||||
outPPSMax=(outPPSMax*999+op)/1000;
|
outPPSMax=(outPPSMax*999+op)/1000;
|
||||||
}
|
}
|
||||||
if(ip>inPPSMax) {
|
if(ip>inPPSMax) {
|
||||||
inPPSMax=(inPPSMax+ip)/2;
|
inPPSMax=ip;
|
||||||
}else {
|
}else {
|
||||||
inPPSMax=(inPPSMax*999+ip)/1000;
|
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;
|
package org.kne.cloud.network.monitor;
|
||||||
|
|
||||||
import org.kne.cloud.clock.HighAccuracyClock;
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
import org.kne.cloud.network.ipv6.PacketID;
|
|
||||||
import org.kne.math.Long128;
|
import org.kne.math.Long128;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,7 +35,10 @@ public interface TimestampMonitor<K> {
|
|||||||
* @return 是否记录成功
|
* @return 是否记录成功
|
||||||
*/
|
*/
|
||||||
boolean recordPacket(K key,int count, int length);
|
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 数据包标识
|
* @param key 数据包标识
|
||||||
@@ -49,8 +51,10 @@ public interface TimestampMonitor<K> {
|
|||||||
|
|
||||||
boolean recordPacket(K key, Long128 timestamp, int count,int length, long dsndDelay);
|
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);
|
||||||
|
|
||||||
// ==================== 清理维护方法 ====================
|
// ==================== 清理维护方法 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -144,9 +148,13 @@ public interface TimestampMonitor<K> {
|
|||||||
TrafficStats calculateTrafficStats(Long128 currentTime, long timeWindowNs);
|
TrafficStats calculateTrafficStats(Long128 currentTime, long timeWindowNs);
|
||||||
|
|
||||||
long getRecentDelay();
|
long getRecentDelay();
|
||||||
|
|
||||||
|
|
||||||
TimestampMonitorValue getRecentDelayEntry();
|
|
||||||
|
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 int length;
|
||||||
private final TimestampMonitorKey<?> key;
|
private final TimestampMonitorKey<?> key;
|
||||||
private long delay;
|
private long delay;
|
||||||
|
private long delayMin;
|
||||||
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp,int count, int length) {
|
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.key = key;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.count=count;
|
this.count=count;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.delay=delay;
|
this.delay=delay;
|
||||||
|
this.delayMin=delayMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
|
result = prime * result + count;
|
||||||
result = prime * result + (int) (delay ^ (delay >>> 32));
|
result = prime * result + (int) (delay ^ (delay >>> 32));
|
||||||
|
result = prime * result + (int) (delayMin ^ (delayMin >>> 32));
|
||||||
result = prime * result + length;
|
result = prime * result + length;
|
||||||
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
|
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
|
||||||
return result;
|
return result;
|
||||||
@@ -38,8 +42,12 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
|||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
TimestampMonitorValue other = (TimestampMonitorValue) obj;
|
TimestampMonitorValue other = (TimestampMonitorValue) obj;
|
||||||
|
if (count != other.count)
|
||||||
|
return false;
|
||||||
if (delay != other.delay)
|
if (delay != other.delay)
|
||||||
return false;
|
return false;
|
||||||
|
if (delayMin != other.delayMin)
|
||||||
|
return false;
|
||||||
if (length != other.length)
|
if (length != other.length)
|
||||||
return false;
|
return false;
|
||||||
if (timestamp == null) {
|
if (timestamp == null) {
|
||||||
@@ -52,8 +60,8 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TimestampMonitorValue [timestamp=" + timestamp + ", length=" + length + ", key=" + key + ", delay="
|
return "TimestampMonitorValue [timestamp=" + timestamp + ", count=" + count + ", length=" + length
|
||||||
+ delay + "]";
|
+ ", delay=" + delay + ", delayMin=" + delayMin + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long128 getTimestamp() { return timestamp; }
|
public Long128 getTimestamp() { return timestamp; }
|
||||||
@@ -73,6 +81,12 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
|||||||
this.delay = delay;
|
this.delay = delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getDelayMin() {
|
||||||
|
return delayMin;
|
||||||
|
}
|
||||||
|
public void setDelayMin(long delayMin) {
|
||||||
|
this.delayMin = delayMin;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(TimestampMonitorValue other) {
|
public int compareTo(TimestampMonitorValue other) {
|
||||||
return this.timestamp.compareTo(other.timestamp);
|
return this.timestamp.compareTo(other.timestamp);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public class NTPContext implements Closeable, AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void putPacket(NTPv4Packet nv4, MultiProtocolSocketAddress inetSocketAddress) {
|
protected void putPacket(NTPv4Packet nv4, MultiProtocolSocketAddress inetSocketAddress) {
|
||||||
checkIP();
|
//checkIP();
|
||||||
List<NTPv4Packet> newv = new Vector<NTPv4Packet>();
|
List<NTPv4Packet> newv = new Vector<NTPv4Packet>();
|
||||||
List<NTPv4Packet> oldv = recvmap.putIfAbsent(inetSocketAddress, newv);
|
List<NTPv4Packet> oldv = recvmap.putIfAbsent(inetSocketAddress, newv);
|
||||||
if (oldv == null) {
|
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 class PeerInfo implements Comparable<PeerInfo> {
|
||||||
private MultiProtocolSocketAddress address;
|
private MultiProtocolSocketAddress address;
|
||||||
@@ -225,14 +206,12 @@ public class NTPContext implements Closeable, AutoCloseable {
|
|||||||
PeerInfo pix = peerInfo.get(0);
|
PeerInfo pix = peerInfo.get(0);
|
||||||
currentClock = pix;
|
currentClock = pix;
|
||||||
int i;
|
int i;
|
||||||
int m = Math.min(peerInfo.size(), 3);
|
List<Long128> adjts = new ArrayList<>();
|
||||||
Long128 bi = Long128.ZERO;
|
for (i = 0; i < peerInfo.size(); i++) {
|
||||||
for (i = 0; i < m; i++) {
|
adjts.add(peerInfo.get(i).getAdj());
|
||||||
PeerInfo pi = peerInfo.get(i);
|
|
||||||
Long128 adjt = pi.getAdj();
|
|
||||||
bi = bi.add(adjt);
|
|
||||||
}
|
}
|
||||||
Long128 delta = bi.divide(Long128.valueOf(i));
|
Long128 delta = NTPTimestamps. median(adjts);
|
||||||
|
//System.out.println(adjts+":"+delta);
|
||||||
avgAdj=(avgAdj*7+delta.abs().longValue())/8;
|
avgAdj=(avgAdj*7+delta.abs().longValue())/8;
|
||||||
Long128 deltaabs=delta.abs();
|
Long128 deltaabs=delta.abs();
|
||||||
if (deltaabs.compareTo(adjustThreshold0) > 0&&firstSync.compareAndSet(true, false)) {
|
if (deltaabs.compareTo(adjustThreshold0) > 0&&firstSync.compareAndSet(true, false)) {
|
||||||
|
|||||||
@@ -252,14 +252,23 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
|||||||
checkLock.unlock();
|
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 {
|
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));
|
nv4.writeToChannel(KNEChannels.newWritableChannel(bbf));
|
||||||
bbf.flip();
|
bbf.flip(); // 切换为读模式,limit 会变成实际写入的长度
|
||||||
|
|
||||||
|
// 3. 发送
|
||||||
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||||
dp.setSocketAddress(target);
|
dp.setSocketAddress(target);
|
||||||
dgs.send(dp);
|
dgs.send(dp);
|
||||||
|
|
||||||
if (showPacket)
|
if (showPacket)
|
||||||
System.out.println("NTPv4 TX:" + target + " " + nv4);
|
System.out.println("NTPv4 TX:" + target + " " + nv4);
|
||||||
}
|
}
|
||||||
@@ -379,15 +388,30 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
|||||||
return sends;
|
return sends;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. 在类成员变量中定义 ThreadLocal 缓冲区
|
||||||
|
private static final ThreadLocal<ByteBuffer> NTP_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(9000));
|
||||||
|
|
||||||
private NTPv4Packet receiveNTPPacket(AtomicReference<InetSocketAddress> isa) throws IOException {
|
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());
|
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||||
dgs.receive(dp);
|
dgs.receive(dp);
|
||||||
|
|
||||||
isa.set((InetSocketAddress) dp.getSocketAddress());
|
isa.set((InetSocketAddress) dp.getSocketAddress());
|
||||||
|
|
||||||
|
// 4. 关键:限制 ByteBuffer 的读取范围,防止越界读取历史脏数据
|
||||||
|
bbf.limit(dp.getLength());
|
||||||
|
|
||||||
NTPv4Packet nv4 = new NTPv4Packet(context.getClock());
|
NTPv4Packet nv4 = new NTPv4Packet(context.getClock());
|
||||||
|
// 5. 将 Channel 的读取操作限制在 dp.getLength() 长度内
|
||||||
nv4.readFromChannel(KNEChannels.newReadableChannel(bbf), dp.getLength());
|
nv4.readFromChannel(KNEChannels.newReadableChannel(bbf), dp.getLength());
|
||||||
|
|
||||||
if (showPacket)
|
if (showPacket)
|
||||||
System.out.println("NTPv4 RX:" + isa.get() + " " + nv4);
|
System.out.println("NTPv4 RX:" + isa.get() + " " + nv4);
|
||||||
|
|
||||||
return nv4;
|
return nv4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,18 +429,5 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
|||||||
return dgs.isClosed();
|
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.nio.channels.UnresolvedAddressException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
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.AdjustedNanoClock;
|
||||||
import org.kne.cloud.clock.HighAccuracyClock;
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
|
import org.kne.cloud.clock.NTPTimestamps;
|
||||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||||
import org.kne.cloud.network.SpeedLimiter;
|
import org.kne.cloud.network.SpeedLimiter;
|
||||||
import org.kne.cloud.network.ThreadTool;
|
import org.kne.cloud.network.ThreadTool;
|
||||||
import org.kne.cloud.network.klalb.KLALBPacket;
|
import org.kne.cloud.network.klalb.*;
|
||||||
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.monitor.LinkStatus;
|
import org.kne.cloud.network.monitor.LinkStatus;
|
||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||||
import org.kne.concurrent.ThreadParker;
|
import org.kne.concurrent.ThreadParker;
|
||||||
|
import org.kne.math.Long128;
|
||||||
|
|
||||||
public class Kperf implements Runnable{
|
public class Kperf implements Runnable{
|
||||||
|
|
||||||
@@ -38,8 +38,8 @@ public class Kperf implements Runnable{
|
|||||||
private volatile KLALBPacketLink link;
|
private volatile KLALBPacketLink link;
|
||||||
|
|
||||||
private LinkStatus status=new LinkStatus();
|
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 boolean closed = false;
|
||||||
|
|
||||||
private volatile ThreadParker tlock=new ThreadParker();
|
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();
|
private long starttime=System.nanoTime();
|
||||||
long totaltime=1000;
|
|
||||||
long usedtime=0;
|
|
||||||
|
|
||||||
|
|
||||||
private MonitorUpdater monitorUpdater;
|
private ScheduledFuture<?> monitorUpdater;
|
||||||
private class MonitorUpdater implements Runnable{
|
private class MonitorUpdater implements Runnable{
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!closed) {
|
if (closed) {
|
||||||
|
monitorUpdater.cancel(false);
|
||||||
|
}else{
|
||||||
status.updateReliability();
|
status.updateReliability();
|
||||||
monitor.update();
|
monitor.update();
|
||||||
try {
|
|
||||||
Thread.sleep(1);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,9 +121,9 @@ public class Kperf implements Runnable{
|
|||||||
});
|
});
|
||||||
Thread tc = ThreadTool.makeVDaemonThreadIfSupport("测速控制线程", () -> {
|
Thread tc = ThreadTool.makeVDaemonThreadIfSupport("测速控制线程", () -> {
|
||||||
final int wtimes=5;
|
final int wtimes=5;
|
||||||
totaltime=(20*1000*1+20*1000*4+wtimes*1000*5)*1000000L;
|
|
||||||
starttime=System.nanoTime();
|
|
||||||
System.out.println("测速开始!");
|
System.out.println("测速开始!");
|
||||||
|
if(reports!=null)
|
||||||
|
reports.updateDial(monitor);
|
||||||
try {
|
try {
|
||||||
long startTime;
|
long startTime;
|
||||||
|
|
||||||
@@ -137,7 +132,6 @@ public class Kperf implements Runnable{
|
|||||||
startTime=System.nanoTime();
|
startTime=System.nanoTime();
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
Thread.sleep(1000);
|
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.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);
|
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:带宽测试");
|
System.out.println("测试2/3:带宽测试");
|
||||||
test.setLimitspeed(1000L*1024L*1024L*1024L);
|
test.setLimitspeed(1000L*1024L*1024L*1024L);
|
||||||
testPacket=new TESTNPacket(65535);
|
testPacket=new TESTNPacket(9000);
|
||||||
for (int i = 0; i < 60; i++) {
|
for (int i = 0; i < 60; i++) {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
}
|
||||||
@@ -208,7 +202,9 @@ public class Kperf implements Runnable{
|
|||||||
|
|
||||||
while ((!link.isClosed()) && (!closed)) {
|
while ((!link.isClosed()) && (!closed)) {
|
||||||
if (checkPingTimeSleep()) {
|
if (checkPingTimeSleep()) {
|
||||||
writePacketToKPL(new PINGPacket(System.nanoTime(),0, 0));
|
PINGPacket ping = new PINGPacket(sysclk.getCurrentTimeNTP64().longValue(), monitor.getOutSpeed(),
|
||||||
|
monitor.getInSpeed());
|
||||||
|
writePacketToKPL(ping);
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
KLALBPacket kpip = IsendDequeList.poll();
|
KLALBPacket kpip = IsendDequeList.poll();
|
||||||
@@ -251,7 +247,17 @@ public class Kperf implements Runnable{
|
|||||||
}
|
}
|
||||||
switch (kpp.getType()) {
|
switch (kpp.getType()) {
|
||||||
case KLALBPacket.PING:
|
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;
|
break;
|
||||||
case KLALBPacket.PONG:
|
case KLALBPacket.PONG:
|
||||||
if (fst) {
|
if (fst) {
|
||||||
@@ -268,44 +274,47 @@ public class Kperf implements Runnable{
|
|||||||
tc.start();
|
tc.start();
|
||||||
fst = false;
|
fst = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PONGPacket png = (PONGPacket) kpp;
|
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();
|
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||||
long DrcvDelayFactor0 = png.getRcvtime() - png.getTimepongsnd();
|
NTPTimestamps.inferNtp64To128(png.getTimepingsnd(), local128));
|
||||||
long DsndDelayFactor;
|
// System.out.println("psnd"+NTPTimestamps.nanosSince1970ToString(
|
||||||
long DrcvDelayFactor;
|
// 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();
|
long DsndDelay = prcv.subtract(psnd).longValue();
|
||||||
try {
|
long DrcvDelay = local.subtract(posnd).longValue();
|
||||||
adjnc.calibrate(png.getTimepongsnd() + ul / 2 - png.getRcvtime(), ul / 2);
|
// System.out.println(DsndDelay+" "+DrcvDelay);
|
||||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
|
||||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
|
||||||
if (DsndDelayFactor < 0) {
|
|
||||||
if (DrcvDelayFactor < 0) {
|
|
||||||
|
|
||||||
} else {
|
long rtt = DsndDelay + DrcvDelay;
|
||||||
adjnc.setDelta(adjnc.getDelta() + DsndDelayFactor);
|
if (DsndDelay >= 0 && DrcvDelay >= 0) {
|
||||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
monitor.recordUploadDelay(DsndDelay);
|
||||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
monitor.recordDownloadDelay(DrcvDelay);
|
||||||
}
|
//sysclk.adjustClock(Long128.valueOf( DsndDelay-DrcvDelay), 0.001);
|
||||||
} else {
|
} else {
|
||||||
if (DrcvDelayFactor < 0) {
|
long Dfallback = rtt / 2;
|
||||||
adjnc.setDelta(adjnc.getDelta() - DrcvDelayFactor);
|
if (Dfallback >= 0) {
|
||||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
monitor.recordUploadDelay(Dfallback);
|
||||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
monitor.recordDownloadDelay(Dfallback);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} finally {
|
// sysclk.adjustClock(Long128.valueOf( DsndDelay-DrcvDelay), 0.1);
|
||||||
adjnc.getLock().unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tlock.unpark();
|
tlock.unpark();
|
||||||
updateUsedTime() ;
|
|
||||||
if(reports!=null)
|
|
||||||
reports.updateDial(monitor);
|
|
||||||
break;
|
break;
|
||||||
case KLALBPacket.TESTN:
|
case KLALBPacket.TESTN:
|
||||||
break;
|
break;
|
||||||
@@ -330,12 +339,7 @@ public class Kperf implements Runnable{
|
|||||||
tcc.interrupt();
|
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() {
|
public void startPerfing() {
|
||||||
monitorUpdater=new MonitorUpdater();
|
monitorUpdater= KLALBScheduler.getScheduler().scheduleWithFixedDelay(new MonitorUpdater(),1,1, TimeUnit.MILLISECONDS);
|
||||||
ThreadTool.makeVDaemonThread("线路性能采样线程", monitorUpdater).start();
|
|
||||||
ThreadTool.makeVDaemonThreadIfSupport("测速接收线程" ,this).start();
|
ThreadTool.makeVDaemonThreadIfSupport("测速接收线程" ,this).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.kne.cloud.network.perf;
|
|||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||||
|
|
||||||
public interface KperfReports {
|
public interface KperfReports {
|
||||||
public void testProcess(double d);
|
|
||||||
public void testFinish();
|
public void testFinish();
|
||||||
public void updateDial(SpeedAndTrafficAndDelayMonitorDataImpl mdt);
|
public void updateDial(SpeedAndTrafficAndDelayMonitorDataImpl mdt);
|
||||||
public void uploadSpeedFinish(long uploadSpeed);
|
public void uploadSpeedFinish(long uploadSpeed);
|
||||||
|
|||||||
@@ -1,73 +1,87 @@
|
|||||||
package org.kne.cloud.network.perf;
|
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.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.ReadableByteChannel;
|
import java.nio.channels.ReadableByteChannel;
|
||||||
import java.nio.channels.WritableByteChannel;
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
import org.kne.cloud.network.ByteBufferAllocator;
|
|
||||||
import org.kne.cloud.network.NetworkPacket;
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
import org.kne.cloud.network.klalb.KLALBPacket;
|
import org.kne.cloud.network.klalb.KLALBPacket;
|
||||||
|
|
||||||
public class TESTNPacket extends KLALBPacket {
|
public class TESTNPacket extends KLALBPacket {
|
||||||
|
|
||||||
private static final int HEADER_LENGTH=3;
|
private static final int HEADER_LENGTH = 3;
|
||||||
|
|
||||||
private ByteBuffer dataBuffer;//=NetworkPacket.databufferpool_65535.borrow();
|
// 核心:一个线程私有的 65535 字节大缓存,生命周期与线程同寿
|
||||||
|
private static final ThreadLocal<ByteBuffer> BENCH_BUFFER =
|
||||||
|
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
|
||||||
|
|
||||||
|
// 不再持有 ByteBuffer,只记录长度
|
||||||
|
private int payloadLength;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getTotalLength() {
|
public long getTotalLength() {
|
||||||
return HEADER_LENGTH+dataBuffer.limit();
|
return HEADER_LENGTH + payloadLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发送端构造
|
||||||
public TESTNPacket(int limit) {
|
public TESTNPacket(int limit) {
|
||||||
super(TESTN,HEADER_LENGTH);
|
super(TESTN, HEADER_LENGTH);
|
||||||
//dataBuffer.limit(limit);
|
this.payloadLength = limit;
|
||||||
dataBuffer=NetworkPacket.bufferAllocator.allocate(limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 接收端构造(从已有的 ByteBuffer 解析)
|
||||||
|
public TESTNPacket(ByteBuffer bb) {
|
||||||
public ByteBuffer getDataBuffer() {
|
super(bb, HEADER_LENGTH);
|
||||||
return dataBuffer;
|
this.payloadLength = klalbHeader.getChar(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getPayloadLength() {
|
||||||
|
return payloadLength;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
||||||
klalbHeader.putChar(1, (char) dataBuffer.limit());
|
// 1. 写入包头(包含 payloadLength)
|
||||||
|
klalbHeader.putChar(1, (char) payloadLength);
|
||||||
super.writeToChannel(dto);
|
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
|
@Override
|
||||||
public void readFromChannel(ReadableByteChannel din) throws IOException {
|
public void readFromChannel(ReadableByteChannel din) throws IOException {
|
||||||
|
// 1. 读包头
|
||||||
super.readFromChannel(din);
|
super.readFromChannel(din);
|
||||||
int limit=klalbHeader.getChar(1);
|
this.payloadLength = klalbHeader.getChar(1);
|
||||||
dataBuffer=NetworkPacket.bufferAllocator.allocate(limit);
|
|
||||||
while(dataBuffer.hasRemaining()){
|
// 2. 如果有 payload,借用缓冲区接收数据
|
||||||
if(din.read(dataBuffer)==-1) {
|
if (payloadLength > 0) {
|
||||||
throw new EOFException();
|
ByteBuffer buf = BENCH_BUFFER.get();
|
||||||
|
buf.clear();
|
||||||
|
buf.limit(payloadLength);
|
||||||
|
|
||||||
|
// 循环读满(使用你现有的 KNEChannels 工具或手动循环)
|
||||||
|
while (buf.hasRemaining()) {
|
||||||
|
if (din.read(buf) == -1) {
|
||||||
|
throw new EOFException("连接提前断开,未能读满 TESTN 载荷");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// 数据读完直接丢弃,缓冲区不保存,下一次 clear() 时会自动覆盖
|
||||||
}
|
}
|
||||||
dataBuffer.flip();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TESTNPacket(ByteBuffer bb) {
|
|
||||||
super(bb,HEADER_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
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.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorData;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorData;
|
||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl;
|
||||||
|
import org.kne.io.KNEChannels;
|
||||||
import org.kne.membandboost.MembandBoost;
|
import org.kne.membandboost.MembandBoost;
|
||||||
|
|
||||||
public class KLALBRoutingProtocol extends Thread{
|
public class KLALBRoutingProtocol extends Thread{
|
||||||
@@ -211,20 +213,15 @@ public class KLALBRoutingProtocol extends Thread{
|
|||||||
while(true) {
|
while(true) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
byte[]ca=MembandBoost.allocateUninitializedByteArray(65535);
|
KLALBRoutingProtocolPacket kp=receivePacket();
|
||||||
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));
|
|
||||||
|
|
||||||
switch(kp.getType()) {
|
switch(kp.getType()) {
|
||||||
case KLALBRoutingProtocolPacket.RINFO_REQ:
|
case KLALBRoutingProtocolPacket.RINFO_REQ:
|
||||||
RouterInfo rifr=netmap.get(router.getLocator().getAddress());
|
RouterInfo rifr=netmap.get(router.getLocator().getAddress());
|
||||||
if(debug)
|
if(debug)
|
||||||
System.out.println("get Request from:"+dgp.getSocketAddress());
|
System.out.println("get Request from:"+kp.getFrom());
|
||||||
if(rifr!=null) {
|
if(rifr!=null) {
|
||||||
writePacket( new RouterInfoPacket( rifr,false,-1), dgp.getSocketAddress());
|
writePacket( new RouterInfoPacket( rifr,false,-1), kp.getFrom());
|
||||||
if(debug)
|
if(debug)
|
||||||
System.out.println("response router info:"+rifr);
|
System.out.println("response router info:"+rifr);
|
||||||
}else {
|
}else {
|
||||||
@@ -246,7 +243,7 @@ public class KLALBRoutingProtocol extends Thread{
|
|||||||
netmap.put(rif.getLocator().getAddress(), rif);
|
netmap.put(rif.getLocator().getAddress(), rif);
|
||||||
noticeUpdate();
|
noticeUpdate();
|
||||||
if(rifp.isFlood()) {
|
if(rifp.isFlood()) {
|
||||||
floodPacket( dgp.getSocketAddress(), rifp);
|
floodPacket( kp.getFrom(), rifp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +256,7 @@ public class KLALBRoutingProtocol extends Thread{
|
|||||||
break;
|
break;
|
||||||
case KLALBRoutingProtocolPacket.JSON_DATA:
|
case KLALBRoutingProtocolPacket.JSON_DATA:
|
||||||
JsonDataPacket data=(JsonDataPacket) kp;
|
JsonDataPacket data=(JsonDataPacket) kp;
|
||||||
receivers.forEach((v)->{v.accept(dgp.getSocketAddress(),data);});
|
receivers.forEach((v)->{v.accept(kp.getFrom(),data);});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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 {
|
private void floodPacket(SocketAddress except,RouterInfoPacket rifp) throws IOException {
|
||||||
long asn=rifp.getASN();
|
long asn=rifp.getASN();
|
||||||
List<Neighbor>ln= router.getNeighbors();
|
List<Neighbor>ln= router.getNeighbors();
|
||||||
@@ -304,20 +326,34 @@ public class KLALBRoutingProtocol extends Thread{
|
|||||||
public void sendJsonPacketToAddress(JsonDataPacket pkt,SocketAddress dest) throws IOException {
|
public void sendJsonPacketToAddress(JsonDataPacket pkt,SocketAddress dest) throws IOException {
|
||||||
writePacket(pkt,dest);
|
writePacket(pkt,dest);
|
||||||
}
|
}
|
||||||
|
// 1. 在类成员变量处定义一个 64KB 的 ThreadLocal 缓冲区
|
||||||
private void writePacket(KLALBRoutingProtocolPacket pkt,SocketAddress dest) throws IOException {
|
// 注意:这里依然使用 65535,因为你说 LSDB 同步可能需要这么大
|
||||||
ByteArrayOutputStream bos=new ByteArrayOutputStream(65535);
|
private static final ThreadLocal<ByteBuffer> LSDB_TX_BUFFER =
|
||||||
KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(Channels.newChannel(bos),pkt);
|
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
|
||||||
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);
|
dgpx.setSocketAddress(dest);
|
||||||
|
|
||||||
sendLock.lock();
|
sendLock.lock();
|
||||||
try {
|
try {
|
||||||
ds.send(dgpx);
|
ds.send(dgpx);
|
||||||
}catch(BindException e) {
|
} catch (BindException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
System.err.println("Cannot assign:"+dest);
|
System.err.println("Cannot assign:" + dest);
|
||||||
}finally {
|
} finally {
|
||||||
sendLock.unlock();
|
sendLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||