KLALB V3.4
@@ -1,12 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry combineaccessrules="false" kind="src" path="/KNElib"/>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/graalvm-jdk-23.0.1+11.1">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/graalvm-jdk-23.0.1+11.1">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="module" value="true"/>
|
<attribute name="module" value="true"/>
|
||||||
<attribute name="add-exports" value="java.base/jdk.internal.misc=ALL-UNNAMED"/>
|
<attribute name="add-exports" value="java.base/jdk.internal.misc=ALL-UNNAMED:java.base/jdk.internal.foreign=ALL-UNNAMED"/>
|
||||||
<attribute name="add-opens" value="java.base/jdk.internal.misc=ALL-UNNAMED"/>
|
<attribute name="add-opens" value="java.base/jdk.internal.misc=ALL-UNNAMED:java.base/jdk.internal.foreign=ALL-UNNAMED"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
<accessrules>
|
<accessrules>
|
||||||
<accessrule kind="accessible" pattern="**"/>
|
<accessrule kind="accessible" pattern="**"/>
|
||||||
@@ -30,5 +29,6 @@
|
|||||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0-javadoc.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/disruptor-4.0.0-sources.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/JavaTUN.jar"/>
|
<classpathentry kind="lib" path="lib/JavaTUN.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/KNElib1.0.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
@@ -1 +1,102 @@
|
|||||||
[{"language":"ZH_CN","nogui":false,"VirtualAddress":"2486:1:0:0:0:0:0:8888","DNS":["2486:1:0:0:0:0:0:8888"],"TCPListen":"0.0.0.0:4565","UDPListen":"{UDP}0.0.0.0:4572","VirtualSocketName":"KLALB_Stream","LineTable":["07f4acdef99b.ofalias.net:4565"],"ConnectLineTable":[],"Type":"KLALBController"},{"Listen":"0.0.0.0:4572","Bridge":{"KLALB":"SocketBridge","RDP":"SocketBridge","HTTP":"SocketBridge","HTTPS":"SocketBridge","DEFAULT":"MinecraftSocketBridge23332"},"Connect":{"KLALB":"127.0.0.1:4565","RDP":"127.0.0.1:3389","HTTP":"127.0.0.1:5212","HTTPS":"192.168.1.235:443","DEFAULT":"127.0.0.1:36555"},"Type":"SocketBridge"},{"Listen":"{KLALB_Stream}[::0]:23332","Bridge":{"DEFAULT":"MinecraftSocketBridge23332"},"Connect":{"DEFAULT":"127.0.0.1:36555"},"Type":"SocketBridge"},{"Listen":"{KLALB_Stream}[::0]:23333","Bridge":{"DEFAULT":"SocketBridge"},"Connect":{"DEFAULT":"127.0.0.1:5212"},"Type":"SocketBridge"},{"Listen":"0.0.0.0:25561","Bridge":{"KLALB":"SocketBridge","DEFAULT":"MinecraftSocketBridge23330"},"Connect":{"KLALB":"127.0.0.1:4565","DEFAULT":"127.0.0.1:25562"},"Type":"SocketBridge"},{"Listen":"{KLALB_Stream}[::0]:23330","Bridge":{"DEFAULT":"MinecraftSocketBridge23330"},"Connect":{"DEFAULT":"127.0.0.1:25562"},"Type":"SocketBridge"}]
|
[
|
||||||
|
{
|
||||||
|
"language": "ZH_CN",
|
||||||
|
"nogui": false,
|
||||||
|
"VirtualAddress": "2486:1:0:0:0:0:0:8888",
|
||||||
|
"VirtualASN": 2142606939373348329,
|
||||||
|
"DNS": [
|
||||||
|
"2486:1:0:0:0:0:0:8888"
|
||||||
|
],
|
||||||
|
"TCPListen": "0.0.0.0:4565",
|
||||||
|
"UDPListen": "{UDP}0.0.0.0:4572",
|
||||||
|
"VirtualSocketName": "KLALB_Stream",
|
||||||
|
"LineTable": [
|
||||||
|
"07f4acdef99b.ofalias.net:4565"
|
||||||
|
],
|
||||||
|
"ConnectLineTable": [
|
||||||
|
"home-ipv6.sliveridc1.cn:4565",
|
||||||
|
"home-ltipv6.sliveridc1.cn:4565"
|
||||||
|
],
|
||||||
|
"ntpServerTable": [
|
||||||
|
"{UDP}ntp1.aliyun.com:123",
|
||||||
|
"{UDP}ntp2.aliyun.com:123",
|
||||||
|
"{UDP}ntp3.aliyun.com:123",
|
||||||
|
"{UDP}ntp4.aliyun.com:123",
|
||||||
|
"{UDP}ntp5.aliyun.com:123",
|
||||||
|
"{UDP}ntp6.aliyun.com:123",
|
||||||
|
"{UDP}ntp7.aliyun.com:123",
|
||||||
|
"{UDP}ntp1.tencent.com:123",
|
||||||
|
"{UDP}ntp2.tencent.com:123",
|
||||||
|
"{UDP}ntp3.tencent.com:123",
|
||||||
|
"{UDP}ntp4.tencent.com:123",
|
||||||
|
"{UDP}ntp5.tencent.com:123",
|
||||||
|
"{UDP}time.google.com:123",
|
||||||
|
"{UDP}time.apple.com:123",
|
||||||
|
"{UDP}pool.ntp.org:123",
|
||||||
|
"{UDP}ntp.ntsc.ac.cn:123",
|
||||||
|
"{UDP}us.ntp.org.cn:123"
|
||||||
|
],
|
||||||
|
"NetworkInterfaceExcepts": [],
|
||||||
|
"Type": "KLALBController"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Listen": "0.0.0.0:4572",
|
||||||
|
"Bridge": {
|
||||||
|
"KLALB": "SocketBridge",
|
||||||
|
"RDP": "SocketBridge",
|
||||||
|
"HTTP": "SocketBridge",
|
||||||
|
"HTTPS": "SocketBridge",
|
||||||
|
"DEFAULT": "MinecraftSocketBridge23332"
|
||||||
|
},
|
||||||
|
"Connect": {
|
||||||
|
"KLALB": "127.0.0.1:4565",
|
||||||
|
"RDP": "127.0.0.1:3389",
|
||||||
|
"HTTP": "127.0.0.1:5212",
|
||||||
|
"HTTPS": "192.168.1.235:443",
|
||||||
|
"DEFAULT": "127.0.0.1:36555"
|
||||||
|
},
|
||||||
|
"Type": "SocketBridge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Listen": "{KLALB_Stream}[::0]:23332",
|
||||||
|
"Bridge": {
|
||||||
|
"DEFAULT": "MinecraftSocketBridge23332"
|
||||||
|
},
|
||||||
|
"Connect": {
|
||||||
|
"DEFAULT": "127.0.0.1:36555"
|
||||||
|
},
|
||||||
|
"Type": "SocketBridge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Listen": "{KLALB_Stream}[::0]:23333",
|
||||||
|
"Bridge": {
|
||||||
|
"DEFAULT": "SocketBridge"
|
||||||
|
},
|
||||||
|
"Connect": {
|
||||||
|
"DEFAULT": "127.0.0.1:5212"
|
||||||
|
},
|
||||||
|
"Type": "SocketBridge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Listen": "0.0.0.0:25561",
|
||||||
|
"Bridge": {
|
||||||
|
"KLALB": "SocketBridge",
|
||||||
|
"DEFAULT": "MinecraftSocketBridge23330"
|
||||||
|
},
|
||||||
|
"Connect": {
|
||||||
|
"KLALB": "127.0.0.1:4565",
|
||||||
|
"DEFAULT": "127.0.0.1:25562"
|
||||||
|
},
|
||||||
|
"Type": "SocketBridge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Listen": "{KLALB_Stream}[::0]:23330",
|
||||||
|
"Bridge": {
|
||||||
|
"DEFAULT": "MinecraftSocketBridge23330"
|
||||||
|
},
|
||||||
|
"Connect": {
|
||||||
|
"DEFAULT": "127.0.0.1:25562"
|
||||||
|
},
|
||||||
|
"Type": "SocketBridge"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -19,6 +19,8 @@ uploadspeed=Upload speed
|
|||||||
downloadspeed=Download speed
|
downloadspeed=Download speed
|
||||||
uploadpps=Upload PPS
|
uploadpps=Upload PPS
|
||||||
downloadpps=Download PPS
|
downloadpps=Download PPS
|
||||||
|
uploaddelay=Upload delay
|
||||||
|
downloaddelay=Download delay
|
||||||
copy=Copy
|
copy=Copy
|
||||||
onlinedevices=Online devices
|
onlinedevices=Online devices
|
||||||
monitor=Monitor
|
monitor=Monitor
|
||||||
@@ -37,6 +39,7 @@ invaildtcplisten=TCP listen:Invaild Input
|
|||||||
invaildudplisten=UDP listen:Invaild Input
|
invaildudplisten=UDP listen:Invaild Input
|
||||||
invaildopenlinetable=Open line table:Invaild Input
|
invaildopenlinetable=Open line table:Invaild Input
|
||||||
invaildconnectlinetable=Connect line table:Invaild Input
|
invaildconnectlinetable=Connect line table:Invaild Input
|
||||||
|
invaildntpservertable=NTP server addresses:Invaild Input
|
||||||
unknown=Unknown
|
unknown=Unknown
|
||||||
viewlinemonitor=View line monitor
|
viewlinemonitor=View line monitor
|
||||||
copylineaddress=Copy line address
|
copylineaddress=Copy line address
|
||||||
@@ -44,4 +47,33 @@ copyvirtualaddress=Copy virtual address
|
|||||||
tryreconnect=Try reconnect
|
tryreconnect=Try reconnect
|
||||||
forcedisconnect=Force disconnect
|
forcedisconnect=Force disconnect
|
||||||
removeline=Remove line
|
removeline=Remove line
|
||||||
|
time=Time
|
||||||
|
speermonitor=Speed monitor
|
||||||
|
delaymonitor=Delay monitor
|
||||||
|
speed=Speed
|
||||||
|
delay=Delay
|
||||||
|
virtualnetsettings=Virtual network settings
|
||||||
|
tunnelnetsettings=Tunnel network settings
|
||||||
|
linksettings=Link settings
|
||||||
|
klalbperf=KLALB-perf Speedtest tool
|
||||||
|
speedtest=Network speed test
|
||||||
|
starttest=Start test
|
||||||
|
testreport=Test report
|
||||||
|
invaildinput=Invaild input
|
||||||
|
stoptest=Stop test
|
||||||
|
bandwidth=Bandwidth
|
||||||
|
nodeinf=Node information
|
||||||
|
selectinterface=Select network interface
|
||||||
|
add=Add
|
||||||
|
edit=Edit
|
||||||
|
remove=Remove
|
||||||
|
networkinterfaceexcept=Network interface except
|
||||||
|
cancel=Cancel
|
||||||
|
ok=Ok
|
||||||
|
currenttime=Current time
|
||||||
|
timesyncsettings=Time sync settings
|
||||||
|
ntpservers=NTP server addresses
|
||||||
|
nodeinfo=Node information
|
||||||
|
basicinfo=Basic info
|
||||||
|
overview=Overview
|
||||||
|
timerange=Time range
|
||||||
@@ -19,6 +19,8 @@ uploadspeed=上传速度
|
|||||||
downloadspeed=下载速度
|
downloadspeed=下载速度
|
||||||
uploadpps=上传包转发率
|
uploadpps=上传包转发率
|
||||||
downloadpps=下载包转发率
|
downloadpps=下载包转发率
|
||||||
|
uploaddelay=上传延迟
|
||||||
|
downloaddelay=下载延迟
|
||||||
copy=复制
|
copy=复制
|
||||||
onlinedevices=在线设备
|
onlinedevices=在线设备
|
||||||
monitor=监视器
|
monitor=监视器
|
||||||
@@ -37,6 +39,7 @@ invaildtcplisten=TCP监听端口:非法输入
|
|||||||
invaildudplisten=UDP监听端口:非法输入
|
invaildudplisten=UDP监听端口:非法输入
|
||||||
invaildopenlinetable=开放线路列表:非法输入
|
invaildopenlinetable=开放线路列表:非法输入
|
||||||
invaildconnectlinetable=自动连接线路列表:非法输入
|
invaildconnectlinetable=自动连接线路列表:非法输入
|
||||||
|
invaildntpservertable==NTP授时服务器地址:非法输入
|
||||||
unknown=未知
|
unknown=未知
|
||||||
viewlinemonitor=打开链路监视器
|
viewlinemonitor=打开链路监视器
|
||||||
copylineaddress=复制链路地址
|
copylineaddress=复制链路地址
|
||||||
@@ -44,4 +47,33 @@ copyvirtualaddress=复制虚拟地址
|
|||||||
tryreconnect=立即尝试重连
|
tryreconnect=立即尝试重连
|
||||||
forcedisconnect=强制断开连接
|
forcedisconnect=强制断开连接
|
||||||
removeline=强制断开连接并移除
|
removeline=强制断开连接并移除
|
||||||
|
time=时间
|
||||||
|
speermonitor=速度监视器
|
||||||
|
delaymonitor=延迟监视器
|
||||||
|
speed=速度
|
||||||
|
delay=延迟
|
||||||
|
virtualnetsettings=虚拟网络设置
|
||||||
|
tunnelnetsettings=隧道网络设置
|
||||||
|
linksettings=链路设置
|
||||||
|
klalbperf=KLALB-perf测速工具
|
||||||
|
speedtest=网速测试
|
||||||
|
starttest=开始测试
|
||||||
|
testreport=测速报告
|
||||||
|
invaildinput=非法输入
|
||||||
|
stoptest=停止测试
|
||||||
|
bandwidth=带宽
|
||||||
|
nodeinf=节点信息
|
||||||
|
selectinterface=选择网卡
|
||||||
|
add=添加
|
||||||
|
edit=编辑
|
||||||
|
remove=移除
|
||||||
|
networkinterfaceexcept=网卡排除列表
|
||||||
|
cancel=取消
|
||||||
|
ok=确定
|
||||||
|
currenttime=当前时间
|
||||||
|
timesyncsettings=时钟同步设置
|
||||||
|
ntpservers=NTP授时服务器地址
|
||||||
|
nodeinfo=节点信息
|
||||||
|
basicinfo=基本信息
|
||||||
|
overview=概览
|
||||||
|
timerange=时间范围
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
package org.kne.cloud.clock;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import org.kne.math.Long128;
|
||||||
|
|
||||||
|
public class HighAccuracyClock {
|
||||||
|
|
||||||
|
|
||||||
|
private final long initialCPUNanoTime;
|
||||||
|
private final Long128 initialSystemNanoTime;
|
||||||
|
private volatile AtomicLong baseCPUNanoTime=new AtomicLong();
|
||||||
|
private volatile Long128 baseSystemNanoTime;
|
||||||
|
|
||||||
|
private volatile long frequency=1000000000;//1000015000
|
||||||
|
|
||||||
|
private ReentrantLock lock=new ReentrantLock();
|
||||||
|
|
||||||
|
private static final Long128 NANOS_PER_MILLIS = Long128.valueOf(TimeUnit.MILLISECONDS.toNanos(1));
|
||||||
|
|
||||||
|
|
||||||
|
private static final Long128 NANOS_PER_SECONDS = Long128.valueOf(TimeUnit.SECONDS.toNanos(1));
|
||||||
|
|
||||||
|
|
||||||
|
public HighAccuracyClock() {
|
||||||
|
this.initialSystemNanoTime =Long128.valueOf( System.currentTimeMillis() ).multiply(NANOS_PER_MILLIS);
|
||||||
|
this.initialCPUNanoTime = System.nanoTime();
|
||||||
|
this.baseSystemNanoTime=initialSystemNanoTime;
|
||||||
|
this.baseCPUNanoTime.set(initialCPUNanoTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getFrequency() {
|
||||||
|
return frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrequency(long frequency) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
long curr=System.nanoTime();
|
||||||
|
long nanoela=curr-baseCPUNanoTime.getAndSet(curr);
|
||||||
|
baseSystemNanoTime=baseSystemNanoTime.add( Long128.valueOf(nanoela).multiply(this.frequency).divide(NANOS_PER_SECONDS));
|
||||||
|
this.frequency = frequency;
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void adjustFrequency(long fdelta) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
compact();
|
||||||
|
this.frequency = frequency+fdelta;
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void compact() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
long curr=System.nanoTime();
|
||||||
|
long nanoela=curr-baseCPUNanoTime.getAndSet(curr);
|
||||||
|
baseSystemNanoTime=baseSystemNanoTime.add(Long128.valueOf(nanoela).multiply(this.frequency).divide(NANOS_PER_SECONDS));
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取从1970-01-01开始的当前时间(纳秒精度)
|
||||||
|
*/
|
||||||
|
public Long128 getCurrentTimeNanos() {
|
||||||
|
Long128 mul=Long128.valueOf(System.nanoTime()-baseCPUNanoTime.get()).multiply(frequency);
|
||||||
|
if(mul.getHigh()!=0) {
|
||||||
|
compact();
|
||||||
|
mul=Long128.valueOf(System.nanoTime()-baseCPUNanoTime.get()).multiply(frequency);
|
||||||
|
}
|
||||||
|
return mul.divide(NANOS_PER_SECONDS).add(baseSystemNanoTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取从1970-01-01开始的当前时间(毫秒精度)
|
||||||
|
*/
|
||||||
|
public long getCurrentTimeMillis() {
|
||||||
|
return getCurrentTimeNanos().divide(NANOS_PER_MILLIS).longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 NTPv4 128 位时间戳
|
||||||
|
*/
|
||||||
|
public BigInteger getCurrentTimeNTP128() {
|
||||||
|
return NTPTimestamps.nanosToNtp128BitTimestamp(getCurrentTimeNanos());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 NTPv4 64 位时间戳
|
||||||
|
*/
|
||||||
|
public BigInteger getCurrentTimeNTP64() {
|
||||||
|
return NTPTimestamps.ntp128To64(getCurrentTimeNTP128());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取时钟创建以来经过的时间(纳秒)
|
||||||
|
*/
|
||||||
|
public long getElapsedNanos() {
|
||||||
|
return System.nanoTime() - initialCPUNanoTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== 修复的时间同步方法 ==================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制同步到指定时间(正确版本)
|
||||||
|
* @param targetNanos 目标时间(从1970年开始的纳秒数)
|
||||||
|
*/
|
||||||
|
public void syncToTime(Long128 targetNanos) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
baseCPUNanoTime.set( System.nanoTime());
|
||||||
|
baseSystemNanoTime=targetNanos;
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于参考时钟进行同步(更安全的方法)
|
||||||
|
* @param referenceClock 参考时钟
|
||||||
|
*/
|
||||||
|
public void syncToClock(HighAccuracyClock referenceClock) {
|
||||||
|
syncToClock(referenceClock,BigInteger.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于参考时钟进行同步(更安全的方法)
|
||||||
|
* @param referenceClock 参考时钟
|
||||||
|
* @param delta 网络延迟(纳秒),可选
|
||||||
|
*/
|
||||||
|
public void syncToClock(HighAccuracyClock referenceClock, BigInteger delta) {
|
||||||
|
if (delta == null) {
|
||||||
|
delta = BigInteger.ZERO;
|
||||||
|
}
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
baseCPUNanoTime.set( System.nanoTime());
|
||||||
|
baseSystemNanoTime=referenceClock.getCurrentTimeNanos();
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于NTP时间戳同步
|
||||||
|
* @param ntp128Timestamp NTP 128位时间戳
|
||||||
|
*/
|
||||||
|
public void syncToNTPTime(BigInteger ntp128Timestamp) {
|
||||||
|
Long128 targetNanos = NTPTimestamps.ntp128BitToNanosTimestamp(ntp128Timestamp);
|
||||||
|
syncToTime(targetNanos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调整时钟(用于时间同步)
|
||||||
|
* @param delta 要调整的纳秒数(正数调快,负数调慢)
|
||||||
|
*/
|
||||||
|
public void adjustClock(Long128 delta) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
baseSystemNanoTime = baseSystemNanoTime.add(delta);
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调整时钟(用于时间同步)
|
||||||
|
* @param delta 要调整的纳秒数(正数调快,负数调慢)
|
||||||
|
*/
|
||||||
|
public void adjustClock(Long128 delta, double adjPercent) {
|
||||||
|
BigInteger adjustment=new BigDecimal(delta.toBigInteger()).multiply(BigDecimal.valueOf( adjPercent)).toBigInteger();
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
baseSystemNanoTime = baseSystemNanoTime.add(Long128 .valueOf(adjustment));
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取时钟偏差(当前时间与真实时间的差异)
|
||||||
|
*/
|
||||||
|
public Long128 getClockError(Long128 referenceTime) {
|
||||||
|
return getCurrentTimeNanos().subtract(referenceTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查时钟是否同步(误差在允许范围内)
|
||||||
|
*/
|
||||||
|
public boolean isSynchronized(Long128 referenceTime, Long128 tolerance) {
|
||||||
|
Long128 error = getClockError(referenceTime).abs();
|
||||||
|
return error.compareTo(tolerance) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ================== toString 方法 ==================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为详细格式的字符串(包含纳秒)
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
Long128 nanos = getCurrentTimeNanos();
|
||||||
|
return NTPTimestamps.nanosSince1970ToString(nanos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getInitialCPUNanoTime() {
|
||||||
|
return initialCPUNanoTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long128 getInitialSystemNanoTime() {
|
||||||
|
return initialSystemNanoTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
HighAccuracyClock hac=new HighAccuracyClock();
|
||||||
|
while(true) {
|
||||||
|
System.out.println(hac.getCurrentTimeNanos());
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,367 @@
|
|||||||
|
package org.kne.cloud.clock;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
import org.kne.math.Long128;
|
||||||
|
|
||||||
|
public class NTPTimestamps {
|
||||||
|
|
||||||
|
// 常量定义
|
||||||
|
public static final BigInteger NANOS_PER_SECOND = BigInteger.valueOf(1_000_000_000L);
|
||||||
|
public static final BigInteger NANOS_PER_MILLIS = BigInteger.valueOf(1_000_000L);
|
||||||
|
|
||||||
|
// NTP 纪元 (1900) 和 Unix 纪元 (1970) 之间的纳秒差
|
||||||
|
public static final BigInteger NTP_EPOCH_OFFSET_NS = BigInteger.valueOf(2208988800L)
|
||||||
|
.multiply(NANOS_PER_SECOND);
|
||||||
|
|
||||||
|
// 2^64 值,用于单位转换
|
||||||
|
public static final BigInteger TWO_POW_64 = BigInteger.ONE.shiftLeft(64);
|
||||||
|
|
||||||
|
// 2^32 值,用于 64 位时间戳处理
|
||||||
|
public static final BigInteger TWO_POW_32 = BigInteger.ONE.shiftLeft(32);
|
||||||
|
|
||||||
|
// 掩码常量
|
||||||
|
public static final BigInteger MASK_32_BIT = new BigInteger("FFFFFFFF", 16);
|
||||||
|
public static final BigInteger MASK_64_BIT = new BigInteger("FFFFFFFFFFFFFFFF", 16);
|
||||||
|
|
||||||
|
// ================== 核心转换方法 ==================
|
||||||
|
// 2^32 秒,约 136.192 年,一个 NTP 纪元的长度
|
||||||
|
public static final BigInteger SECONDS_PER_ERA = BigInteger.valueOf(0x100000000L);
|
||||||
|
|
||||||
|
public static BigInteger inferNtp64To128(long remote64Bit,BigInteger local128Bit ) {
|
||||||
|
return inferNtp64To128(toUnsignedBigInteger(remote64Bit),local128Bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据本地 128 位时间戳和网络 64 位时间戳,推断并补全纪元信息
|
||||||
|
*
|
||||||
|
* @param remote64Bit 从网络接收的 64 位 NTP 时间戳
|
||||||
|
* @param local128Bit 本地已知的 128 位 NTP 时间戳
|
||||||
|
* @return 推断出的完整 128 位 NTP 时间戳
|
||||||
|
*/
|
||||||
|
public static BigInteger inferNtp64To128(BigInteger remote64Bit,BigInteger local128Bit ) {
|
||||||
|
// 1. 从本地 128 位时间戳中提取纪元号和 64 位时间戳部分
|
||||||
|
BigInteger localEra = NTPTimestamps.getEraNumber(local128Bit);
|
||||||
|
BigInteger local64Bit = NTPTimestamps.getNtp64Timestamp(local128Bit);
|
||||||
|
|
||||||
|
// 3. 计算本地和远程 64 位时间戳的差异
|
||||||
|
BigInteger difference = remote64Bit.subtract(local64Bit);
|
||||||
|
|
||||||
|
// 4. 判断纪元关系并推断远程时间戳的纪元
|
||||||
|
BigInteger remoteEra;
|
||||||
|
|
||||||
|
// 如果差异很大(超过半个纪元),可能需要调整纪元
|
||||||
|
BigInteger halfEra = BigInteger.valueOf(Long.MAX_VALUE);
|
||||||
|
|
||||||
|
if (difference.compareTo(halfEra) > 0) {
|
||||||
|
// 远程时间戳比本地小很多,可能属于上一个纪元
|
||||||
|
remoteEra = localEra.subtract(BigInteger.ONE);
|
||||||
|
} else if (difference.compareTo(halfEra.negate()) < 0) {
|
||||||
|
// 远程时间戳比本地大很多,可能属于下一个纪元
|
||||||
|
remoteEra = localEra.add(BigInteger.ONE);
|
||||||
|
} else {
|
||||||
|
// 差异不大,属于同一个纪元
|
||||||
|
remoteEra = localEra;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 组合纪元号和 64 位时间戳,得到完整的 128 位时间戳
|
||||||
|
return NTPTimestamps.ntp64To128(remote64Bit, remoteEra);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 将从1970年开始的纳秒数转换为 NTPv4 128 位时间戳
|
||||||
|
* 128位时间戳表示从1900年1月1日起经过的 2⁻⁶⁴ 秒的数量
|
||||||
|
*/
|
||||||
|
public static BigInteger nanosToNtp128BitTimestamp(Long128 nanosSince1970) {
|
||||||
|
// 1. 计算从 1900 年开始的总纳秒数
|
||||||
|
BigInteger totalNanosFrom1900 = nanosSince1970.toBigInteger().add(NTP_EPOCH_OFFSET_NS);
|
||||||
|
|
||||||
|
// 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
|
||||||
|
return totalNanosFrom1900.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 NTPv4 128 位时间戳转换回从1970年开始的纳秒数
|
||||||
|
*/
|
||||||
|
public static Long128 ntp128BitToNanosTimestamp(BigInteger ntp128Timestamp) {
|
||||||
|
// 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
|
||||||
|
BigInteger totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||||
|
|
||||||
|
// 2. 计算从 1970 年开始的总纳秒数
|
||||||
|
return Long128.valueOf( totalNanosFrom1900.subtract(NTP_EPOCH_OFFSET_NS));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static BigInteger nanosToNtp128BitTimeInterval(BigInteger nanos) {
|
||||||
|
// 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
|
||||||
|
return nanos.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static BigInteger ntp128BitToNanosInterval(BigInteger ntp128Timestamp) {
|
||||||
|
// 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
|
||||||
|
BigInteger totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||||
|
|
||||||
|
return totalNanosFrom1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ================== 128位 ↔ 64位 转换 ==================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 NTP 128 位时间戳转换为 NTP 64 位时间戳
|
||||||
|
* 64位时间戳就是128位时间戳的中间64位
|
||||||
|
*/
|
||||||
|
public static BigInteger ntp128To64(BigInteger ntp128Timestamp) {
|
||||||
|
return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 NTP 64 位时间戳转换为 NTP 128 位时间戳
|
||||||
|
* 64位时间戳放在128位时间戳的中间64位,高32位Era和低32位分数为0
|
||||||
|
*/
|
||||||
|
public static BigInteger ntp64To128(BigInteger ntp64Timestamp) {
|
||||||
|
return ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 NTP 64 位时间戳转换为 NTP 128 位时间戳(指定Era Number)
|
||||||
|
*/
|
||||||
|
public static BigInteger ntp64To128(BigInteger ntp64Timestamp, BigInteger eraNumber) {
|
||||||
|
return eraNumber.and(MASK_32_BIT).shiftLeft(96)
|
||||||
|
.or(ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 NTP 128 位时间戳中提取 Era Number(高32位)
|
||||||
|
*/
|
||||||
|
public static BigInteger getEraNumber(BigInteger ntp128Timestamp) {
|
||||||
|
return ntp128Timestamp.shiftRight(96).and(MASK_32_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 NTP 128 位时间戳中提取 64 位时间戳(中间64位)
|
||||||
|
*/
|
||||||
|
public static BigInteger getNtp64Timestamp(BigInteger ntp128Timestamp) {
|
||||||
|
return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 NTP 128 位时间戳中提取分数部分(低32位)
|
||||||
|
*/
|
||||||
|
public static BigInteger getFraction(BigInteger ntp128Timestamp) {
|
||||||
|
return ntp128Timestamp.and(MASK_32_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== 工具方法 ==================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从毫秒和纳秒偏移构造 BigInteger 纳秒
|
||||||
|
*/
|
||||||
|
public static Long128 toNanosSince1970(long unixTimeMillis, long nanosOffset) {
|
||||||
|
return Long128.valueOf(unixTimeMillis)
|
||||||
|
.multiply(Long128.valueOf( NANOS_PER_MILLIS))
|
||||||
|
.add(Long128.valueOf(nanosOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 BigInteger 纳秒提取毫秒和纳秒偏移
|
||||||
|
*/
|
||||||
|
public static long[] toMillisAndNanos(Long128 nanosSince1970) {
|
||||||
|
Long128[] millisAndNanos = nanosSince1970.divideAndRemainder(Long128.valueOf( NANOS_PER_MILLIS));
|
||||||
|
return new long[]{millisAndNanos[0].longValue(), millisAndNanos[1].longValue()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两个 128 位时间戳之间的时间差(纳秒)
|
||||||
|
*/
|
||||||
|
public static BigInteger calculateTimeDifference(BigInteger timestamp1, BigInteger timestamp2) {
|
||||||
|
BigInteger diff = timestamp2.subtract(timestamp1);
|
||||||
|
return diff.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 64 位 NTP 时间戳分解为秒数和分数
|
||||||
|
*/
|
||||||
|
public static BigInteger[] parseNtp64Timestamp(BigInteger ntp64Timestamp) {
|
||||||
|
BigInteger seconds = ntp64Timestamp.shiftRight(32).and(MASK_32_BIT);
|
||||||
|
BigInteger fraction = ntp64Timestamp.and(MASK_32_BIT);
|
||||||
|
return new BigInteger[]{seconds, fraction};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从秒数和分数构建 64 位 NTP 时间戳
|
||||||
|
*/
|
||||||
|
public static BigInteger buildNtp64Timestamp(BigInteger seconds, BigInteger fraction) {
|
||||||
|
return seconds.and(MASK_32_BIT).shiftLeft(32).or(fraction.and(MASK_32_BIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== 测试代码 ==================
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("=== NTPv4 128位/64位时间戳转换测试 ===");
|
||||||
|
|
||||||
|
// 测试当前时间
|
||||||
|
testCurrentTime();
|
||||||
|
|
||||||
|
// 测试 128位 ↔ 64位 转换
|
||||||
|
test128To64Conversion();
|
||||||
|
|
||||||
|
// 测试 Era Number 处理
|
||||||
|
testEraNumberHandling();
|
||||||
|
|
||||||
|
// 测试边界值
|
||||||
|
testBoundaryValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testCurrentTime() {
|
||||||
|
System.out.println("\n=== 当前时间测试 ===");
|
||||||
|
|
||||||
|
Long128 nanosSince1970 = toNanosSince1970(System.currentTimeMillis(), 123456);
|
||||||
|
BigInteger ntp128 = nanosToNtp128BitTimestamp(nanosSince1970);
|
||||||
|
BigInteger ntp64 = ntp128To64(ntp128);
|
||||||
|
|
||||||
|
System.out.println("从1970年开始的纳秒数: " + nanosSince1970);
|
||||||
|
System.out.println("NTP 128-bit: 0x" + ntp128.toString(16).toUpperCase());
|
||||||
|
System.out.println("NTP 64-bit: 0x" + ntp64.toString(16).toUpperCase());
|
||||||
|
|
||||||
|
// 反向转换验证
|
||||||
|
BigInteger recovered128 = ntp64To128(ntp64);
|
||||||
|
Long128 recoveredNanos = ntp128BitToNanosTimestamp(recovered128);
|
||||||
|
|
||||||
|
System.out.println("恢复的纳秒数: " + recoveredNanos);
|
||||||
|
System.out.println("转换正确: " + (nanosSince1970.equals(recoveredNanos) ? "✅" : "❌"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test128To64Conversion() {
|
||||||
|
System.out.println("\n=== 128位 ↔ 64位 转换测试 ===");
|
||||||
|
|
||||||
|
// 创建一个测试用的 128 位时间戳
|
||||||
|
BigInteger test128 = new BigInteger("EC652B7E912F00B81234567890ABCDEF", 16);
|
||||||
|
|
||||||
|
BigInteger ntp64 = ntp128To64(test128);
|
||||||
|
BigInteger recovered128 = ntp64To128(ntp64);
|
||||||
|
|
||||||
|
System.out.println("原始128位: 0x" + test128.toString(16).toUpperCase());
|
||||||
|
System.out.println("转换64位: 0x" + ntp64.toString(16).toUpperCase());
|
||||||
|
System.out.println("恢复128位: 0x" + recovered128.toString(16).toUpperCase());
|
||||||
|
|
||||||
|
// 验证中间64位相同
|
||||||
|
BigInteger original64Part = getNtp64Timestamp(test128);
|
||||||
|
System.out.println("转换正确: " + (original64Part.equals(ntp64) ? "✅" : "❌"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testEraNumberHandling() {
|
||||||
|
System.out.println("\n=== Era Number 处理测试 ===");
|
||||||
|
|
||||||
|
BigInteger ntp64 = new BigInteger("EC652B7E912F00B8", 16);
|
||||||
|
BigInteger eraNumber = new BigInteger("1", 16); // Era 1
|
||||||
|
|
||||||
|
BigInteger ntp128WithEra = ntp64To128(ntp64, eraNumber);
|
||||||
|
BigInteger extractedEra = getEraNumber(ntp128WithEra);
|
||||||
|
BigInteger extracted64 = getNtp64Timestamp(ntp128WithEra);
|
||||||
|
|
||||||
|
System.out.println("设置 Era: 0x" + eraNumber.toString(16).toUpperCase());
|
||||||
|
System.out.println("提取 Era: 0x" + extractedEra.toString(16).toUpperCase());
|
||||||
|
System.out.println("提取 64位: 0x" + extracted64.toString(16).toUpperCase());
|
||||||
|
System.out.println("128位值: 0x" + ntp128WithEra.toString(16).toUpperCase());
|
||||||
|
System.out.println("Era 正确: " + (eraNumber.equals(extractedEra) ? "✅" : "❌"));
|
||||||
|
System.out.println("64位正确: " + (ntp64.equals(extracted64) ? "✅" : "❌"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testBoundaryValues() {
|
||||||
|
System.out.println("\n=== 边界值测试 ===");
|
||||||
|
|
||||||
|
// 测试最大值
|
||||||
|
BigInteger max64 = MASK_64_BIT; // 0xFFFFFFFFFFFFFFFF
|
||||||
|
BigInteger max128 = ntp64To128(max64);
|
||||||
|
BigInteger recovered64 = ntp128To64(max128);
|
||||||
|
|
||||||
|
System.out.println("最大64位: 0x" + max64.toString(16).toUpperCase());
|
||||||
|
System.out.println("转换128位: 0x" + max128.toString(16).toUpperCase());
|
||||||
|
System.out.println("恢复64位: 0x" + recovered64.toString(16).toUpperCase());
|
||||||
|
System.out.println("最大值转换正确: " + (max64.equals(recovered64) ? "✅" : "❌"));
|
||||||
|
|
||||||
|
// 测试 Era Number 边界
|
||||||
|
BigInteger maxEra = MASK_32_BIT; // 0xFFFFFFFF
|
||||||
|
BigInteger test64 = new BigInteger("1234567890ABCDEF", 16);
|
||||||
|
BigInteger ntp128MaxEra = ntp64To128(test64, maxEra);
|
||||||
|
BigInteger extractedMaxEra = getEraNumber(ntp128MaxEra);
|
||||||
|
|
||||||
|
System.out.println("最大Era转换正确: " + (maxEra.equals(extractedMaxEra) ? "✅" : "❌"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成时间序列测试
|
||||||
|
*/
|
||||||
|
public static void testTimeSeries() {
|
||||||
|
System.out.println("\n=== 时间序列测试 ===");
|
||||||
|
|
||||||
|
Long128 startNanos = toNanosSince1970(System.currentTimeMillis(), 0);
|
||||||
|
BigInteger start128 = nanosToNtp128BitTimestamp(startNanos);
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
Long128 offsetNanos = Long128.valueOf(i).multiply(Long128.valueOf( NANOS_PER_SECOND).divide(Long128.valueOf(10)));
|
||||||
|
Long128 currentNanos = startNanos.add(offsetNanos);
|
||||||
|
BigInteger current128 = nanosToNtp128BitTimestamp(currentNanos);
|
||||||
|
BigInteger current64 = ntp128To64(current128);
|
||||||
|
|
||||||
|
long[] time = toMillisAndNanos(currentNanos);
|
||||||
|
System.out.printf("时间: %d ms + %d ns -> 64位: %s -> 128位: %s%n",
|
||||||
|
time[0], time[1],
|
||||||
|
current64.toString(16).toUpperCase(),
|
||||||
|
current128.toString(16).toUpperCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 日期时间格式化器
|
||||||
|
private static final DateTimeFormatter DEFAULT_FORMATTER =
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
|
||||||
|
private static final DateTimeFormatter DETAILED_FORMATTER =
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.n");
|
||||||
|
public static String nanosSince1970ToString(Long128 nanos) {
|
||||||
|
Long128 millis = nanos.divide(Long128.valueOf(1_000_000));
|
||||||
|
Long128 nanosPart = nanos.mod(Long128.valueOf(1_000_000));
|
||||||
|
|
||||||
|
Instant instant = Instant.ofEpochMilli(millis.longValue());
|
||||||
|
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||||
|
|
||||||
|
return String.format("%s.%06d",
|
||||||
|
DEFAULT_FORMATTER.format(dateTime),
|
||||||
|
nanosPart.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 128 位时间戳转换为可读字符串
|
||||||
|
*/
|
||||||
|
public static String ntp128ToString(BigInteger ntp128Timestamp) {
|
||||||
|
Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp128Timestamp);
|
||||||
|
return nanosSince1970ToString(nanosSince1970);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 64 位时间戳转换为可读字符串
|
||||||
|
*/
|
||||||
|
public static String ntp64ToString(BigInteger ntp64Timestamp) {
|
||||||
|
Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp64To128( ntp64Timestamp));
|
||||||
|
return nanosSince1970ToString(nanosSince1970);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BigInteger toUnsignedBigInteger(long unsignedLong) {
|
||||||
|
if (unsignedLong >= 0) {
|
||||||
|
return BigInteger.valueOf(unsignedLong);
|
||||||
|
} else {
|
||||||
|
// 对于负数,通过添加 2^64 来转换为无符号表示
|
||||||
|
return BigInteger.valueOf(unsignedLong & 0x7FFFFFFFFFFFFFFFL)
|
||||||
|
.setBit(63);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ import java.awt.Image;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@@ -63,6 +65,8 @@ public abstract class ListSettingItem<T> extends SettingItem {
|
|||||||
jbt3x.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/add.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
jbt3x.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/add.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
}catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
jbt3x.setSize(dss);
|
jbt3x.setSize(dss);
|
||||||
jbt3x.setPreferredSize(dss);
|
jbt3x.setPreferredSize(dss);
|
||||||
@@ -70,8 +74,9 @@ public abstract class ListSettingItem<T> extends SettingItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
T x=createEmpty();
|
List<T> x=createEmpty();
|
||||||
runEdit(x);
|
if(x!=null&&!x.isEmpty())
|
||||||
|
runEdit(x.get(0));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
JButton jbedit=new JButton();
|
JButton jbedit=new JButton();
|
||||||
@@ -80,6 +85,8 @@ public abstract class ListSettingItem<T> extends SettingItem {
|
|||||||
jbedit.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/edit-fill.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
jbedit.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/edit-fill.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
}catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
jbedit.setSize(dss);
|
jbedit.setSize(dss);
|
||||||
jbedit.setPreferredSize(dss);
|
jbedit.setPreferredSize(dss);
|
||||||
@@ -99,6 +106,8 @@ public abstract class ListSettingItem<T> extends SettingItem {
|
|||||||
jbt4x.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/delete-bin-fill.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
jbt4x.setIcon(new ImageIcon(ImageIO .read(ListSettingItem.class.getResourceAsStream("/assets/delete-bin-fill.png")).getScaledInstance(dss.width-2, dss.height-2, Image.SCALE_SMOOTH)));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
}catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
jbt4x.setSize(dss);
|
jbt4x.setSize(dss);
|
||||||
jbt4x.setPreferredSize(dss);
|
jbt4x.setPreferredSize(dss);
|
||||||
@@ -125,7 +134,7 @@ public abstract class ListSettingItem<T> extends SettingItem {
|
|||||||
jp.add(jbt4x);
|
jp.add(jbt4x);
|
||||||
}
|
}
|
||||||
abstract protected void runEdit(T val) ;
|
abstract protected void runEdit(T val) ;
|
||||||
abstract protected T createEmpty() ;
|
abstract protected List<T> createEmpty() ;
|
||||||
public void doAdd(T v) {
|
public void doAdd(T v) {
|
||||||
boolean b=true;
|
boolean b=true;
|
||||||
for (int i = 0; i < list.getModel().getSize(); i++) {
|
for (int i = 0; i < list.getModel().getSize(); i++) {
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
package org.kne.cloud.network;
|
||||||
|
|
||||||
|
import java.lang.foreign.Arena;
|
||||||
|
import java.lang.foreign.MemorySegment;
|
||||||
|
import java.lang.foreign.MemorySegment.Scope;
|
||||||
|
import java.lang.ref.PhantomReference;
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.ReferenceQueue;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
public class BufferedArena implements Arena{
|
||||||
|
private static long blockSize=10*1024L*1024L;
|
||||||
|
private volatile PreAlloc buffer;
|
||||||
|
private static ReferenceQueue<MemorySegment> refq=new ReferenceQueue<>();
|
||||||
|
private static MemorySegmentPool msp=new MemorySegmentPool(1000, blockSize,true);
|
||||||
|
|
||||||
|
public static long getBlockSize() {
|
||||||
|
return blockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void setBlockSize(long blockSizex) {
|
||||||
|
blockSize = blockSizex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private ReentrantLock lock=new ReentrantLock();
|
||||||
|
|
||||||
|
private class PreAlloc{
|
||||||
|
private MemorySegment segment;
|
||||||
|
private AtomicLong pos=new AtomicLong(0);
|
||||||
|
private AtomicLong refs=new AtomicLong(0);
|
||||||
|
public MemorySegment getSegment() {
|
||||||
|
return segment;
|
||||||
|
}
|
||||||
|
public AtomicLong getPos() {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
public PreAlloc(MemorySegment segment) {
|
||||||
|
super();
|
||||||
|
this.segment = segment;
|
||||||
|
}
|
||||||
|
public long byteSize() {
|
||||||
|
return segment.byteSize();
|
||||||
|
}
|
||||||
|
public AtomicLong getRefs() {
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void allocateNew(long blockSize2) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
//buffer=Arena.ofAuto().allocate(blockSize);
|
||||||
|
MemorySegment raw=msp.borrow();
|
||||||
|
buffer=new PreAlloc(raw);
|
||||||
|
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
Thread t= new Thread(()->{
|
||||||
|
while(true) {
|
||||||
|
try {
|
||||||
|
Reference<? extends MemorySegment> ref;
|
||||||
|
ref = refq.remove();
|
||||||
|
if(ref!=null) {
|
||||||
|
ref.clear();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// TODO 自动生成的 catch 块
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t.setDaemon(true);
|
||||||
|
t.setPriority(Thread.MAX_PRIORITY-1);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public BufferedArena() {
|
||||||
|
super();
|
||||||
|
allocateNew(blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemorySegment allocate(long byteSize, long byteAlignment) {
|
||||||
|
if(byteSize>blockSize)
|
||||||
|
throw new IndexOutOfBoundsException("byteSize can't large than buffer block");
|
||||||
|
long pos;
|
||||||
|
PreAlloc bufferx;
|
||||||
|
do{
|
||||||
|
bufferx=this.buffer;
|
||||||
|
pos=bufferx.getPos().getAndAdd(byteSize);
|
||||||
|
if(pos+byteSize>bufferx.byteSize()) {
|
||||||
|
allocateNew(blockSize);
|
||||||
|
}else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}while(true);
|
||||||
|
bufferx.getRefs().incrementAndGet();
|
||||||
|
MemorySegment sliced=bufferx.getSegment().asSlice(pos, byteSize);
|
||||||
|
new MemorySegmentPhantomReference(sliced, refq, bufferx, msp);
|
||||||
|
return sliced;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Scope scope() {
|
||||||
|
return Arena.ofAuto().scope();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
Arena.ofAuto().close();
|
||||||
|
}
|
||||||
|
public static BufferedArena ofBuffered() {
|
||||||
|
return new BufferedArena();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MemorySegmentPhantomReference extends PhantomReference<MemorySegment>{
|
||||||
|
|
||||||
|
private static AtomicReference<MemorySegmentPhantomReference> first=new AtomicReference<>(null);
|
||||||
|
|
||||||
|
private AtomicReference<MemorySegmentPhantomReference> next=new AtomicReference<>(null);
|
||||||
|
private AtomicReference<MemorySegmentPhantomReference> prev=new AtomicReference<>(null);
|
||||||
|
|
||||||
|
private PreAlloc father;
|
||||||
|
private MemorySegmentPool pool;
|
||||||
|
|
||||||
|
public MemorySegmentPhantomReference(MemorySegment referent, ReferenceQueue<? super MemorySegment> q,PreAlloc bufferx,MemorySegmentPool pool) {
|
||||||
|
super(referent, q);
|
||||||
|
this.father=bufferx;
|
||||||
|
this.pool=pool;
|
||||||
|
insert();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insert() {
|
||||||
|
MemorySegmentPhantomReference refn= first.getAndSet(this);
|
||||||
|
if(refn!=null) {
|
||||||
|
next.set(refn);
|
||||||
|
refn.prev.set(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void remove() {
|
||||||
|
MemorySegmentPhantomReference prevn= prev.getAndSet(null);
|
||||||
|
MemorySegmentPhantomReference nextn=next.getAndSet(null);
|
||||||
|
if(prevn!=null)
|
||||||
|
prevn.next.set(nextn);
|
||||||
|
if(nextn!=null)
|
||||||
|
nextn.prev.set(prevn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
if(father.getRefs().decrementAndGet()<=0) {
|
||||||
|
if(buffer!=father)
|
||||||
|
pool.back(father.getSegment());
|
||||||
|
}
|
||||||
|
remove();
|
||||||
|
super.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,445 @@
|
|||||||
|
package org.kne.cloud.network;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修复的BufferedChannel,解决Socket关闭时的数据一致性问题
|
||||||
|
*/
|
||||||
|
public class BufferedChannel implements ReadableByteChannel, WritableByteChannel, ScatteringByteChannel, GatheringByteChannel {
|
||||||
|
private final ReadableByteChannel inputChannel;
|
||||||
|
private final WritableByteChannel outputChannel;
|
||||||
|
private final ByteBuffer readBuffer;
|
||||||
|
private final ByteBuffer writeBuffer;
|
||||||
|
|
||||||
|
private final ReentrantLock readLock = new ReentrantLock();
|
||||||
|
private final ReentrantLock writeLock = new ReentrantLock();
|
||||||
|
|
||||||
|
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||||
|
private final AtomicBoolean inputShutdown = new AtomicBoolean(false);
|
||||||
|
private final AtomicBoolean outputShutdown = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
public BufferedChannel(ReadableByteChannel channel, int bufferSize) {
|
||||||
|
this(channel, null, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedChannel(WritableByteChannel channel, int bufferSize) {
|
||||||
|
this(null, channel, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedChannel(ReadableByteChannel inputChannel, WritableByteChannel outputChannel, int bufferSize) {
|
||||||
|
this.inputChannel = inputChannel;
|
||||||
|
this.outputChannel = outputChannel;
|
||||||
|
this.readBuffer = ByteBuffer.allocateDirect(bufferSize);
|
||||||
|
this.writeBuffer = ByteBuffer.allocateDirect(bufferSize);
|
||||||
|
|
||||||
|
// 更安全的初始化
|
||||||
|
this.readBuffer.limit(0); // 明确设置为空
|
||||||
|
this.writeBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(ByteBuffer dst) throws IOException {
|
||||||
|
if (closed.get() || inputShutdown.get()) {
|
||||||
|
throw new ClosedChannelException();
|
||||||
|
}
|
||||||
|
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
// 检查底层通道是否仍然打开
|
||||||
|
if (inputChannel != null && !inputChannel.isOpen()) {
|
||||||
|
inputShutdown.set(true);
|
||||||
|
return handleInputShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalRead = 0;
|
||||||
|
boolean eofEncountered = false;
|
||||||
|
|
||||||
|
while (dst.hasRemaining() && !eofEncountered) {
|
||||||
|
// 如果读缓冲区有数据,先从中读取
|
||||||
|
if (readBuffer.hasRemaining()) {
|
||||||
|
int bytesToCopy = Math.min(readBuffer.remaining(), dst.remaining());
|
||||||
|
|
||||||
|
// 使用绝对位置操作,避免修改缓冲区状态
|
||||||
|
int oldlimit=readBuffer.limit();
|
||||||
|
readBuffer.limit(readBuffer.position()+bytesToCopy);
|
||||||
|
dst.put(readBuffer);
|
||||||
|
readBuffer.limit(oldlimit);
|
||||||
|
|
||||||
|
totalRead += bytesToCopy;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读缓冲区空了,需要重新填充
|
||||||
|
readBuffer.clear();
|
||||||
|
int bytesRead;
|
||||||
|
try {
|
||||||
|
bytesRead = inputChannel.read(readBuffer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// 读取时发生IO异常,标记为关闭
|
||||||
|
inputShutdown.set(true);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesRead == -1) {
|
||||||
|
// 到达EOF
|
||||||
|
inputShutdown.set(true);
|
||||||
|
eofEncountered = true;
|
||||||
|
} else if (bytesRead == 0) {
|
||||||
|
// 没有数据可用,可能是非阻塞模式
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
readBuffer.flip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果遇到EOF且没有读取到任何数据,返回-1
|
||||||
|
if (eofEncountered && totalRead == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalRead;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理输入关闭的情况
|
||||||
|
*/
|
||||||
|
private int handleInputShutdown() throws IOException {
|
||||||
|
// 如果读缓冲区还有剩余数据,先返回这些数据
|
||||||
|
if (readBuffer.hasRemaining()) {
|
||||||
|
return readBuffer.remaining();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long read(ByteBuffer[] dsts) throws IOException {
|
||||||
|
return read(dsts, 0, dsts.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
|
||||||
|
if (closed.get() || inputShutdown.get()) {
|
||||||
|
throw new ClosedChannelException();
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalRead = 0;
|
||||||
|
for (int i = offset; i < offset + length; i++) {
|
||||||
|
ByteBuffer dst = dsts[i];
|
||||||
|
if (dst == null) {
|
||||||
|
throw new NullPointerException("Destination buffer is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytesRead = read(dst);
|
||||||
|
if (bytesRead == -1) {
|
||||||
|
// 只有在没有读取任何数据时才返回-1
|
||||||
|
return totalRead > 0 ? totalRead : -1;
|
||||||
|
}
|
||||||
|
totalRead += bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int write(ByteBuffer src) throws IOException {
|
||||||
|
if (closed.get() || outputShutdown.get()) {
|
||||||
|
throw new ClosedChannelException();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
// 检查底层通道是否仍然打开
|
||||||
|
if (outputChannel != null && !outputChannel.isOpen()) {
|
||||||
|
outputShutdown.set(true);
|
||||||
|
throw new ClosedChannelException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalWritten = 0;
|
||||||
|
|
||||||
|
while (src.hasRemaining()) {
|
||||||
|
// 如果写缓冲区有空间,先填充
|
||||||
|
if (writeBuffer.hasRemaining()) {
|
||||||
|
int bytesToCopy = Math.min(writeBuffer.remaining(), src.remaining());
|
||||||
|
int oldlimit= src.limit();
|
||||||
|
src.limit(src.position()+bytesToCopy);
|
||||||
|
writeBuffer.put(src);
|
||||||
|
src.limit(oldlimit);
|
||||||
|
|
||||||
|
totalWritten += bytesToCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果写缓冲区满了或者源数据还很多,刷新缓冲区
|
||||||
|
if (!writeBuffer.hasRemaining() ) {
|
||||||
|
try {
|
||||||
|
flushInternal();
|
||||||
|
} catch (IOException e) {
|
||||||
|
outputShutdown.set(true);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totalWritten;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long write(ByteBuffer[] srcs) throws IOException {
|
||||||
|
return write(srcs, 0, srcs.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
|
||||||
|
if (closed.get() || outputShutdown.get()) {
|
||||||
|
throw new ClosedChannelException();
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalWritten = 0;
|
||||||
|
for (int i = offset; i < offset + length; i++) {
|
||||||
|
ByteBuffer src = srcs[i];
|
||||||
|
if (src == null) {
|
||||||
|
throw new NullPointerException("Source buffer is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytesWritten = write(src);
|
||||||
|
totalWritten += bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全的刷新方法
|
||||||
|
*/
|
||||||
|
public void flush() throws IOException {
|
||||||
|
if (closed.get()) {
|
||||||
|
throw new ClosedChannelException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputChannel == null || outputShutdown.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
flushInternal();
|
||||||
|
} catch (IOException e) {
|
||||||
|
outputShutdown.set(true);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部刷新方法,假设已经持有writeLock
|
||||||
|
*/
|
||||||
|
private void flushInternal() throws IOException {
|
||||||
|
if (writeBuffer.position() > 0) {
|
||||||
|
writeBuffer.flip();
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (writeBuffer.hasRemaining()) {
|
||||||
|
int written = outputChannel.write(writeBuffer);
|
||||||
|
// System.out.println("发送"+written);
|
||||||
|
if (written == 0) {
|
||||||
|
// 可能遇到阻塞或关闭
|
||||||
|
if (!outputChannel.isOpen()) {
|
||||||
|
outputShutdown.set(true);
|
||||||
|
throw new ClosedChannelException();
|
||||||
|
}
|
||||||
|
// 给其他操作机会
|
||||||
|
Thread.yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// 无论发生什么,确保写缓冲区处于可写状态
|
||||||
|
writeBuffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全的关闭方法
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (!closed.compareAndSet(false, true)) {
|
||||||
|
return; // 已经关闭
|
||||||
|
}
|
||||||
|
|
||||||
|
IOException exception = null;
|
||||||
|
|
||||||
|
// 先刷新输出缓冲区
|
||||||
|
if (outputChannel != null && !outputShutdown.get()) {
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
if (writeBuffer.position() > 0) {
|
||||||
|
try {
|
||||||
|
flushInternal();
|
||||||
|
} catch (IOException e) {
|
||||||
|
exception = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭底层通道
|
||||||
|
try {
|
||||||
|
if (inputChannel != null) {
|
||||||
|
inputChannel.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (exception == null) {
|
||||||
|
exception = e;
|
||||||
|
} else {
|
||||||
|
exception.addSuppressed(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (outputChannel != null) {
|
||||||
|
outputChannel.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (exception == null) {
|
||||||
|
exception = e;
|
||||||
|
} else {
|
||||||
|
exception.addSuppressed(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理缓冲区状态
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
readBuffer.clear();
|
||||||
|
readBuffer.limit(0); // 标记为已清空
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
writeBuffer.clear();
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置关闭状态
|
||||||
|
inputShutdown.set(true);
|
||||||
|
outputShutdown.set(true);
|
||||||
|
|
||||||
|
if (exception != null) {
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优雅关闭 - 只关闭输入或输出
|
||||||
|
*/
|
||||||
|
public void shutdownInput() throws IOException {
|
||||||
|
inputShutdown.set(true);
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
readBuffer.clear();
|
||||||
|
readBuffer.limit(0);
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputChannel instanceof SocketChannel) {
|
||||||
|
((SocketChannel) inputChannel).shutdownInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdownOutput() throws IOException {
|
||||||
|
outputShutdown.set(true);
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
if (writeBuffer.position() > 0) {
|
||||||
|
flushInternal();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputChannel instanceof SocketChannel) {
|
||||||
|
((SocketChannel) outputChannel).shutdownOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return !closed.get() &&
|
||||||
|
(inputChannel == null || inputChannel.isOpen()) &&
|
||||||
|
(outputChannel == null || outputChannel.isOpen());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否还有可读数据(包括缓冲区中的)
|
||||||
|
*/
|
||||||
|
public boolean hasRemaining() throws IOException {
|
||||||
|
if (closed.get() || inputShutdown.get()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
return readBuffer.hasRemaining() ||
|
||||||
|
(inputChannel != null && inputChannel.isOpen());
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓冲区状态信息(用于调试)
|
||||||
|
*/
|
||||||
|
public String getBufferState() {
|
||||||
|
readLock.lock();
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
return String.format(
|
||||||
|
"ReadBuffer[pos=%d, lim=%d, cap=%d], WriteBuffer[pos=%d, lim=%d, cap=%d], " +
|
||||||
|
"closed=%b, inputShutdown=%b, outputShutdown=%b",
|
||||||
|
readBuffer.position(), readBuffer.limit(), readBuffer.capacity(),
|
||||||
|
writeBuffer.position(), writeBuffer.limit(), writeBuffer.capacity(),
|
||||||
|
closed.get(), inputShutdown.get(), outputShutdown.get()
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他方法保持不变...
|
||||||
|
public int available() throws IOException {
|
||||||
|
if (closed.get() || inputShutdown.get()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
return readBuffer.remaining();
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long skip(long n) throws IOException {
|
||||||
|
// 实现保持不变...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package org.kne.cloud.network;
|
package org.kne.cloud.network;
|
||||||
|
|
||||||
|
import java.lang.foreign.Arena;
|
||||||
|
import java.lang.foreign.MemorySegment;
|
||||||
|
import java.lang.foreign.SegmentAllocator;
|
||||||
import java.lang.ref.Cleaner;
|
import java.lang.ref.Cleaner;
|
||||||
import java.lang.ref.PhantomReference;
|
import java.lang.ref.PhantomReference;
|
||||||
import java.lang.ref.Reference;
|
import java.lang.ref.Reference;
|
||||||
@@ -18,66 +21,41 @@ import org.kne.debug.TimeDebugger;
|
|||||||
|
|
||||||
import jdk.internal.misc.Unsafe;
|
import jdk.internal.misc.Unsafe;
|
||||||
public class ByteBufferAllocator {
|
public class ByteBufferAllocator {
|
||||||
private List<ByteBufferPool> bbfps=new ArrayList<>();
|
static Thread t;
|
||||||
|
static {
|
||||||
private ByteBufferPool[]bbfpsarr;
|
t=new Thread(()->{
|
||||||
|
|
||||||
|
|
||||||
private ReferenceQueue<ByteBuffer> refq=new ReferenceQueue<>();
|
|
||||||
private boolean isDirect;
|
|
||||||
|
|
||||||
public ByteBufferAllocator(boolean isDirect) {
|
|
||||||
this.isDirect=isDirect;
|
|
||||||
int i=1;
|
|
||||||
int maxi=0;
|
|
||||||
int mps=16;
|
|
||||||
for (int j = 0; j < 18; j++) {
|
|
||||||
int count=100;
|
|
||||||
mps+=count;
|
|
||||||
bbfps.add(new ByteBufferPool(mps, i,isDirect));
|
|
||||||
maxi=i;
|
|
||||||
i<<=1;
|
|
||||||
}
|
|
||||||
bbfpsarr=new ByteBufferPool[maxi];
|
|
||||||
for (int j = 0; j < bbfpsarr.length; j++) {
|
|
||||||
bbfpsarr[j]=getByteBufferPool(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread t= new Thread(()->{
|
|
||||||
while(true) {
|
while(true) {
|
||||||
|
System.gc();
|
||||||
try {
|
try {
|
||||||
Reference<? extends ByteBuffer> ref;
|
Thread.sleep(1000);
|
||||||
ref = refq.remove();
|
|
||||||
if(ref!=null) {
|
|
||||||
ref.clear();
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// TODO 自动生成的 catch 块
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
t.setDaemon(true);
|
||||||
t.setPriority(Thread.MAX_PRIORITY-1);
|
t.setPriority(Thread.MAX_PRIORITY-1);
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
public ByteBuffer allocate(int capacity) {
|
|
||||||
if(true) {
|
public ByteBufferAllocator(boolean isDirect) {
|
||||||
return allocateHeap(capacity);
|
|
||||||
}
|
|
||||||
//new Exception().printStackTrace();
|
|
||||||
ByteBufferPool bbfp=bbfpsarr[capacity];
|
|
||||||
ByteBuffer bbf=null;
|
|
||||||
try {
|
|
||||||
bbf=bbfp.borrow();
|
|
||||||
}catch(OutOfMemoryError err) {
|
|
||||||
System.gc();
|
|
||||||
Thread.yield();
|
|
||||||
bbf=bbfp.borrow();
|
|
||||||
}
|
|
||||||
ByteBuffer bbfs=bbf.slice(0, capacity);
|
|
||||||
|
|
||||||
new ByteBufferPhantomReference(bbfs,refq,bbf,bbfp);
|
}
|
||||||
return bbfs;
|
public ByteBuffer allocate(int capacity) {
|
||||||
|
//if(capacity<1024)
|
||||||
|
return allocateHeap(capacity);
|
||||||
|
//return allocateNative(capacity);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
//private Arena ar=BufferedArena.ofBuffered();
|
||||||
|
private Arena ara=Arena.ofAuto();
|
||||||
|
public ByteBuffer allocateNative(int capacity) {
|
||||||
|
//return ((jdk.internal.foreign.ArenaImpl)Arena.ofAuto()).allocateNoInit(capacity,1).asByteBuffer();
|
||||||
|
|
||||||
|
ByteBuffer buf=Arena.ofAuto().allocate(capacity).asByteBuffer();
|
||||||
|
if(buf.capacity()!=capacity)
|
||||||
|
throw new InternalError();
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
private static jdk.internal.misc.Unsafe usf;
|
private static jdk.internal.misc.Unsafe usf;
|
||||||
private static Method meth;
|
private static Method meth;
|
||||||
@@ -97,30 +75,23 @@ public class ByteBufferAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ByteBuffer allocateHeap(int capacity) {
|
public static byte[] allocateArray(int capacity) {
|
||||||
//return ByteBuffer.wrap((byte[]) usf.allocateUninitializedArray(byte.class, capacity));
|
|
||||||
if(usf!=null&&meth!=null) {
|
if(usf!=null&&meth!=null) {
|
||||||
try {
|
try {
|
||||||
return ByteBuffer.wrap((byte[]) usf.allocateUninitializedArray(byte.class, capacity));
|
return (byte[]) usf.allocateUninitializedArray(byte.class, capacity);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return ByteBuffer.wrap(new byte[capacity]);
|
return new byte[capacity];
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
return ByteBuffer.wrap(new byte[capacity]);
|
return new byte[capacity];
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private ByteBufferPool getByteBufferPool(int capacity) {
|
|
||||||
int elen=0;
|
|
||||||
for (int i = 0; i < bbfps.size(); i++) {
|
|
||||||
ByteBufferPool bfp=bbfps.get(i);
|
|
||||||
if(capacity<=(elen= bfp.getLength())) {
|
|
||||||
return bfp;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
throw new RuntimeException("capacity:"+capacity+">"+elen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ByteBuffer allocateHeap(int capacity) {
|
||||||
|
return ByteBuffer.wrap((byte[])allocateArray(capacity)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class ByteBufferPhantomReference extends PhantomReference<ByteBuffer>{
|
private static class ByteBufferPhantomReference extends PhantomReference<ByteBuffer>{
|
||||||
|
|
||||||
private static AtomicReference<ByteBufferPhantomReference> first=new AtomicReference<>(null);
|
private static AtomicReference<ByteBufferPhantomReference> first=new AtomicReference<>(null);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class DatagramServerSocket implements java.io.Closeable{
|
|||||||
private final Object stateLock = new Object();
|
private final Object stateLock = new Object();
|
||||||
private BlockingQueue<DatagramSocket> recs;
|
private BlockingQueue<DatagramSocket> recs;
|
||||||
private InetSocketAddress bindpoint;
|
private InetSocketAddress bindpoint;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ public class DatagramServerSocket implements java.io.Closeable{
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
while(true) {
|
while(!closed) {
|
||||||
byte[]data=dataarraypool.borrow();
|
byte[]data=dataarraypool.borrow();
|
||||||
DatagramPacket dp=new DatagramPacket(data,data.length);
|
DatagramPacket dp=new DatagramPacket(data,data.length);
|
||||||
datagramSocket.receive(dp);
|
datagramSocket.receive(dp);
|
||||||
@@ -179,6 +179,10 @@ public class DatagramServerSocket implements java.io.Closeable{
|
|||||||
public void removeClient(SubDatagramSocket subDatagramSocket) {
|
public void removeClient(SubDatagramSocket subDatagramSocket) {
|
||||||
clients.remove(subDatagramSocket.getRemoteSocketAddress());
|
clients.remove(subDatagramSocket.getRemoteSocketAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
datagramSocket.close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public DatagramSocket accept()throws IOException{
|
public DatagramSocket accept()throws IOException{
|
||||||
@@ -341,6 +345,10 @@ public class DatagramServerSocket implements java.io.Closeable{
|
|||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
closed=true;
|
closed=true;
|
||||||
|
for (Iterator<DatagramDistributor> iterator = skts.iterator(); iterator.hasNext();) {
|
||||||
|
DatagramDistributor datagramSocket = (DatagramDistributor) iterator.next();
|
||||||
|
datagramSocket.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketAddress getLocalSocketAddress() {
|
public SocketAddress getLocalSocketAddress() {
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package org.kne.cloud.network;
|
||||||
|
|
||||||
|
import java.lang.foreign.Arena;
|
||||||
|
import java.lang.foreign.MemorySegment;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import org.kne.concurrent.SpinLock;
|
||||||
|
import org.kne.debug.TimeDebugger;
|
||||||
|
|
||||||
|
|
||||||
|
public class MemorySegmentPool {
|
||||||
|
private AtomicReferenceArray< MemorySegment> rec;
|
||||||
|
private volatile AtomicInteger pos=new AtomicInteger( 0);
|
||||||
|
//private Lock lock=new SpinLock();
|
||||||
|
|
||||||
|
private int maxcount;
|
||||||
|
private long length;
|
||||||
|
private int mcj;
|
||||||
|
private boolean direct;
|
||||||
|
public MemorySegmentPool(int maxcount, long length,boolean direct) {
|
||||||
|
super();
|
||||||
|
this.maxcount = maxcount;
|
||||||
|
this.length = length;
|
||||||
|
this.direct=direct;
|
||||||
|
rec=new AtomicReferenceArray<MemorySegment>(maxcount);
|
||||||
|
mcj= rec.length()-1;
|
||||||
|
}
|
||||||
|
public MemorySegmentPool(int maxcount, int length) {
|
||||||
|
this(maxcount, length, true);
|
||||||
|
}
|
||||||
|
public void back(MemorySegment b) {
|
||||||
|
if(b.byteSize()!=length)
|
||||||
|
throw new IllegalArgumentException("wrong length");
|
||||||
|
|
||||||
|
|
||||||
|
if(pos.get()<=mcj) {
|
||||||
|
int d=pos.getAndIncrement();
|
||||||
|
if(d>mcj)
|
||||||
|
d=mcj;
|
||||||
|
if(d<0)
|
||||||
|
d=0;
|
||||||
|
rec.compareAndSet(d,null,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public MemorySegment borrow() {
|
||||||
|
MemorySegment b=null;
|
||||||
|
|
||||||
|
if(pos.get()>0) {
|
||||||
|
int d=pos.decrementAndGet();
|
||||||
|
if(d>mcj)
|
||||||
|
d=mcj;
|
||||||
|
if(d<0)
|
||||||
|
d=0;
|
||||||
|
b=rec.getAndSet(d,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b==null) {
|
||||||
|
ByteBufferAllocator.t.interrupt();
|
||||||
|
if(direct) {
|
||||||
|
b=((jdk.internal.foreign.ArenaImpl)Arena.ofAuto()).allocateNoInit(length,1);
|
||||||
|
System.out.println(length);
|
||||||
|
}else {
|
||||||
|
b=MemorySegment.ofArray(new byte[(int) length]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
public int getMaxCount() {
|
||||||
|
return maxcount;
|
||||||
|
}
|
||||||
|
public long getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -99,6 +99,31 @@ public class MultipurposeSocketAddress implements Serializable{
|
|||||||
return Objects.equals(host, other.host) && port == other.port && Objects.equals(ps, other.ps)
|
return Objects.equals(host, other.host) && port == other.port && Objects.equals(ps, other.ps)
|
||||||
&& Objects.equals(type, other.type);
|
&& Objects.equals(type, other.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean equals2(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
MultipurposeSocketAddress other = (MultipurposeSocketAddress) obj;
|
||||||
|
InetAddress addra=null;
|
||||||
|
try {
|
||||||
|
addra = InetAddress.getByName(host);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
}
|
||||||
|
InetAddress addrb=null;
|
||||||
|
try {
|
||||||
|
addrb = InetAddress.getByName(other.host);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
}
|
||||||
|
boolean hostequals=Objects.equals(addra, addrb);
|
||||||
|
|
||||||
|
return hostequals && port == other.port && Objects.equals(ps, other.ps)
|
||||||
|
&& Objects.equals(type, other.type);
|
||||||
|
}
|
||||||
|
|
||||||
public MultipurposeSocketAddress(String host2, int port2) {
|
public MultipurposeSocketAddress(String host2, int port2) {
|
||||||
this("TCP", host2, port2);
|
this("TCP", host2, port2);
|
||||||
}
|
}
|
||||||
@@ -116,6 +141,8 @@ public class MultipurposeSocketAddress implements Serializable{
|
|||||||
port=remoteSocketAddress.getPort();
|
port=remoteSocketAddress.getPort();
|
||||||
this.type=type;
|
this.type=type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
@@ -125,6 +152,11 @@ public class MultipurposeSocketAddress implements Serializable{
|
|||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress getSocketAddress() {
|
||||||
|
return new InetSocketAddress(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb=new StringBuilder();
|
StringBuilder sb=new StringBuilder();
|
||||||
@@ -367,6 +399,23 @@ public class MultipurposeSocketAddress implements Serializable{
|
|||||||
}
|
}
|
||||||
return dgd;
|
return dgd;
|
||||||
}
|
}
|
||||||
|
public DatagramSocket listenDatagramSocket() throws UnknownHostException, IOException {
|
||||||
|
DatagramSocketFactory dgs=socketTypeRegister.get(type).getDatagramSocketFactory();
|
||||||
|
System.out.println(dgs);
|
||||||
|
if(dgs==null) {
|
||||||
|
throw new UnsupportedOperationException("DatagramSocket Unsupported");
|
||||||
|
}
|
||||||
|
DatagramSocket dgd=dgs.createSocket();
|
||||||
|
try {
|
||||||
|
dgd.bind(new InetSocketAddress(host, port));
|
||||||
|
}catch(Exception e) {
|
||||||
|
dgd.close();
|
||||||
|
System.gc();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return dgd;
|
||||||
|
}
|
||||||
|
|
||||||
public DatagramServerSocket listenDatagramServerSocket() throws UnknownHostException, IOException {
|
public DatagramServerSocket listenDatagramServerSocket() throws UnknownHostException, IOException {
|
||||||
DatagramServerSocketFactory srf=socketTypeRegister.get(type).getDatagramServerSocketFactory();
|
DatagramServerSocketFactory srf=socketTypeRegister.get(type).getDatagramServerSocketFactory();
|
||||||
if(srf==null) {
|
if(srf==null) {
|
||||||
@@ -430,4 +479,5 @@ public class MultipurposeSocketAddress implements Serializable{
|
|||||||
gsonBuilder.registerTypeAdapter(MultipurposeSocketAddress.class, getDefaultJsonDeserializer());
|
gsonBuilder.registerTypeAdapter(MultipurposeSocketAddress.class, getDefaultJsonDeserializer());
|
||||||
gsonBuilder.registerTypeAdapter(MultipurposeSocketAddress.class, getDefaultJsonSerializer());
|
gsonBuilder.registerTypeAdapter(MultipurposeSocketAddress.class, getDefaultJsonSerializer());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public abstract class NetworkPacket implements Comparable<NetworkPacket>{
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public abstract long getLength();
|
public abstract long getTotalLength();
|
||||||
|
|
||||||
public long getPriority() {
|
public long getPriority() {
|
||||||
return priority;
|
return priority;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class SpeedLimiter {
|
|||||||
return hitlimit;
|
return hitlimit;
|
||||||
}
|
}
|
||||||
private volatile long limitspeed=1024*1024;
|
private volatile long limitspeed=1024*1024;
|
||||||
private long brustTime=1000000L;
|
private long brustTime=2000000L;
|
||||||
private volatile boolean hitlimit=false;
|
private volatile boolean hitlimit=false;
|
||||||
public long getLimitspeed() {
|
public long getLimitspeed() {
|
||||||
return limitspeed;
|
return limitspeed;
|
||||||
@@ -43,7 +43,8 @@ public class SpeedLimiter {
|
|||||||
private AtomicLong waitingtime=new AtomicLong();
|
private AtomicLong waitingtime=new AtomicLong();
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SpeedLimiter [limitspeed=" + limitspeed + "]";
|
return "SpeedLimiter [limitspeed=" + limitspeed + ", brustTime=" + brustTime + ", hitlimit=" + hitlimit
|
||||||
|
+ ", ltime=" + ltime + ", waitingtime=" + waitingtime + "]";
|
||||||
}
|
}
|
||||||
public void forceTransmit(long datasize) {
|
public void forceTransmit(long datasize) {
|
||||||
long limitspeedx=limitspeed;
|
long limitspeedx=limitspeed;
|
||||||
@@ -60,7 +61,7 @@ public class SpeedLimiter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
waitingtime.addAndGet(datasize*1000000000L/limitspeedx);
|
waitingtime.addAndGet((long) (datasize*1000000000.0/limitspeedx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//用系统计时器的时刻相减得到经过的时间,与数据包除以限速值得到的应消耗的时间做对比,若时间还未到达发送下一个数据包的时机,则返回false
|
//用系统计时器的时刻相减得到经过的时间,与数据包除以限速值得到的应消耗的时间做对比,若时间还未到达发送下一个数据包的时机,则返回false
|
||||||
@@ -83,17 +84,18 @@ public class SpeedLimiter {
|
|||||||
|
|
||||||
});
|
});
|
||||||
if(nv<=brustTime) {
|
if(nv<=brustTime) {
|
||||||
waitingtime.addAndGet(datasize*1000000000L/limitspeedx);
|
|
||||||
//System.out.println(limitspeed);
|
|
||||||
return true;
|
return true;
|
||||||
}else {
|
}else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void transmit(long datasize) {
|
public void transmit(long datasize) {
|
||||||
|
long limitspeedx=limitspeed;
|
||||||
while(!checkTransmit(datasize)) {
|
while(!checkTransmit(datasize)) {
|
||||||
LockSupport.parkNanos(100000);
|
//LockSupport.parkNanos(100000);
|
||||||
|
Thread.yield();
|
||||||
}
|
}
|
||||||
|
waitingtime.addAndGet((long) (datasize*1000000000.0/limitspeedx));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.kne.cloud.network;
|
||||||
|
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
|
||||||
|
public class VirtualDatagramSocket extends DatagramSocket {
|
||||||
|
private VirtualDatagramSocketImpl virtualImpl;
|
||||||
|
|
||||||
|
protected VirtualDatagramSocketImpl getVirtualImpl() {
|
||||||
|
return virtualImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualDatagramSocket(VirtualDatagramSocketImpl si) throws SocketException {
|
||||||
|
super(si);
|
||||||
|
this.virtualImpl=si;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.kne.cloud.network;
|
||||||
|
|
||||||
|
import java.net.DatagramSocketImpl;
|
||||||
|
|
||||||
|
public abstract class VirtualDatagramSocketImpl extends DatagramSocketImpl{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class BBRCongressAlgorithm implements CongressAlgorithm {
|
||||||
|
|
||||||
|
private static final long BURST_TIME = 2000000L;
|
||||||
|
private static final long BIAS = 2000000L;
|
||||||
|
private static long MIN_SPEED = 128 * 1024L;
|
||||||
|
private static long MIN_WINDOW = 16384;
|
||||||
|
|
||||||
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
private BiConsumer<Long, Long> speedControlConsumer;
|
||||||
|
|
||||||
|
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||||
|
private long MIN_RTTVAR = 50000000L;
|
||||||
|
private volatile long RTTMin = 1000000000L;
|
||||||
|
private volatile long RTTVar = 1000000000L;
|
||||||
|
private volatile long RTTAvg = 1000000000L;
|
||||||
|
private volatile long RTTAvg2 = 1000000000L;
|
||||||
|
private volatile long RTTTotal = 0;
|
||||||
|
private volatile long RTTCount = 0;
|
||||||
|
private volatile long RTO = 1000000000L;
|
||||||
|
|
||||||
|
|
||||||
|
private volatile long window=MIN_WINDOW;
|
||||||
|
private volatile long speed=MIN_SPEED;
|
||||||
|
private volatile long maxwindow=99999999999L;
|
||||||
|
private long congressSpeed=MIN_SPEED;
|
||||||
|
private double MAX_GAIN=1.02;//2.8853900817779
|
||||||
|
private double MIN_GAIN=0.9;
|
||||||
|
private double windowGain=MAX_GAIN;
|
||||||
|
private double speedGain=MAX_GAIN;
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
window = MIN_WINDOW;
|
||||||
|
if (windowControlConsumer != null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
speed = MIN_SPEED;
|
||||||
|
if (speedControlConsumer != null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
windowGain=MAX_GAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||||
|
this.windowControlConsumer = windowControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||||
|
this.speedControlConsumer = speedControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long RTTstartTime = System.nanoTime();
|
||||||
|
private long bandwidth;
|
||||||
|
@Override
|
||||||
|
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||||
|
if (latencyns <= RTTMin) {
|
||||||
|
RTTMin = latencyns;
|
||||||
|
} else {
|
||||||
|
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||||
|
}
|
||||||
|
if (firstUpdate.compareAndSet(true, false)) {
|
||||||
|
RTTAvg = latencyns;
|
||||||
|
RTTVar = latencyns / 2;
|
||||||
|
RTTAvg2 = latencyns;
|
||||||
|
} else {
|
||||||
|
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||||
|
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||||
|
}
|
||||||
|
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||||
|
|
||||||
|
RTTTotal += latencyns;
|
||||||
|
RTTCount++;
|
||||||
|
long curr=System.nanoTime();
|
||||||
|
if(curr-RTTstartTime>RTTAvg2) {
|
||||||
|
if(RTTCount>0) {
|
||||||
|
RTTAvg2=(RTTAvg2+RTTTotal/RTTCount)/2;
|
||||||
|
RTTTotal=0;
|
||||||
|
RTTCount=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTTstartTime=curr;
|
||||||
|
|
||||||
|
if (bandwidth >= congressSpeed) {
|
||||||
|
congressSpeed = bandwidth;
|
||||||
|
//congressSpeed = (congressSpeed + bandwidth) / 2;
|
||||||
|
} else {
|
||||||
|
congressSpeed = (congressSpeed * 199 + bandwidth) / 200;
|
||||||
|
}
|
||||||
|
speed=MIN_SPEED+(long) (congressSpeed * speedGain) ;
|
||||||
|
window= (Math.max(MIN_SPEED,(long) (congressSpeed*windowGain ))*(RTTMin+1000000L)/1000000000L)+MIN_WINDOW;
|
||||||
|
if (windowControlConsumer != null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
if (speedControlConsumer != null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRTO() {
|
||||||
|
return RTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentWindowUsed(long used) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentBandwidth(long bandwidth) {
|
||||||
|
this.bandwidth=bandwidth;
|
||||||
|
|
||||||
|
//System.out.println(gain);
|
||||||
|
//System.out.println(bandwidth+" "+congressSpeed+" "+window);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class BBRVegasCongressAlgorithm implements CongressAlgorithm {
|
||||||
|
|
||||||
|
private static final long BURST_TIME = 2000000L;
|
||||||
|
private static final long BIAS = 2000000L;
|
||||||
|
private static long MIN_SPEED = 128 * 1024L;
|
||||||
|
private static long MIN_WINDOW = 8192;
|
||||||
|
|
||||||
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
private BiConsumer<Long, Long> speedControlConsumer;
|
||||||
|
|
||||||
|
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||||
|
private long MIN_RTTVAR = 50000000L;
|
||||||
|
private volatile long RTTMin = 1000000000L;
|
||||||
|
private volatile long RTTVar = 1000000000L;
|
||||||
|
private volatile long RTTAvg = 1000000000L;
|
||||||
|
private volatile long RTTAvg2 = 1000000000L;
|
||||||
|
private volatile long RTTTotal = 0;
|
||||||
|
private volatile long RTTCount = 0;
|
||||||
|
private volatile long RTO = 1000000000L;
|
||||||
|
|
||||||
|
|
||||||
|
private volatile long window=MIN_WINDOW;
|
||||||
|
private volatile long speed=MIN_SPEED;
|
||||||
|
private volatile long maxwindow=99999999999L;
|
||||||
|
private long congressSpeed=MIN_SPEED;
|
||||||
|
private double MAX_GAIN=2.8853900817779;//2.8853900817779
|
||||||
|
private double MIN_GAIN=1.1;
|
||||||
|
private double gain=MAX_GAIN;
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
window = MIN_WINDOW;
|
||||||
|
if (windowControlConsumer != null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
speed = MIN_SPEED;
|
||||||
|
if (speedControlConsumer != null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
gain=MAX_GAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||||
|
this.windowControlConsumer = windowControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||||
|
this.speedControlConsumer = speedControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long RTTstartTime = System.nanoTime();
|
||||||
|
@Override
|
||||||
|
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||||
|
if (latencyns <= RTTMin) {
|
||||||
|
RTTMin = latencyns;
|
||||||
|
} else {
|
||||||
|
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||||
|
}
|
||||||
|
if (firstUpdate.compareAndSet(true, false)) {
|
||||||
|
RTTAvg = latencyns;
|
||||||
|
RTTVar = latencyns / 2;
|
||||||
|
RTTAvg2 = latencyns;
|
||||||
|
} else {
|
||||||
|
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||||
|
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||||
|
}
|
||||||
|
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||||
|
|
||||||
|
RTTTotal += latencyns;
|
||||||
|
RTTCount++;
|
||||||
|
long curr=System.nanoTime();
|
||||||
|
if(curr-RTTstartTime>RTTMin) {
|
||||||
|
if(RTTCount>0) {
|
||||||
|
RTTAvg2=(RTTAvg2+RTTTotal/RTTCount)/2;
|
||||||
|
RTTTotal=0;
|
||||||
|
RTTCount=0;
|
||||||
|
}
|
||||||
|
long RTTAvg2x=Math.max(RTTAvg2-BIAS,RTTMin);
|
||||||
|
double excepted=window/(double)RTTMin;
|
||||||
|
double actual=window/(double)RTTAvg2x;
|
||||||
|
double diff=(excepted-actual)*RTTMin;
|
||||||
|
if(diff>65536*3+3) {
|
||||||
|
gain-=0.0005;
|
||||||
|
}
|
||||||
|
if(diff<65536*3+1) {
|
||||||
|
gain+=0.0005;
|
||||||
|
}
|
||||||
|
if(gain>=MAX_GAIN){
|
||||||
|
gain=MAX_GAIN;
|
||||||
|
//System.out.println("window:"+window);
|
||||||
|
}
|
||||||
|
if(gain<MIN_GAIN) {
|
||||||
|
gain=MIN_GAIN;
|
||||||
|
//System.out.println("window:"+window);
|
||||||
|
}
|
||||||
|
RTTstartTime=curr;
|
||||||
|
|
||||||
|
}
|
||||||
|
//System.out.println(speed+" "+window);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRTO() {
|
||||||
|
return RTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentWindowUsed(long used) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentBandwidth(long bandwidth) {
|
||||||
|
/*if (bandwidth >= congressSpeed) {
|
||||||
|
congressSpeed = (congressSpeed * 49 + bandwidth) / 50;
|
||||||
|
} else {
|
||||||
|
congressSpeed = (congressSpeed *2 + bandwidth) / 3;
|
||||||
|
}*/
|
||||||
|
if (bandwidth >= congressSpeed) {
|
||||||
|
//congressSpeed = bandwidth;
|
||||||
|
congressSpeed = (congressSpeed + bandwidth) / 2;
|
||||||
|
} else {
|
||||||
|
congressSpeed = (congressSpeed * 49 + bandwidth) / 50;
|
||||||
|
}
|
||||||
|
speed=Math.max(MIN_SPEED,(long) (congressSpeed * gain)) ;
|
||||||
|
window=Math.max( (Math.max(MIN_SPEED,(long) (congressSpeed*gain ))*Math.max(2000000L,RTTMin)/1000000000L),MIN_WINDOW);
|
||||||
|
if (windowControlConsumer != null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
if (speedControlConsumer != null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
//System.out.println(gain);
|
||||||
|
//System.out.println(bandwidth+" "+congressSpeed+" "+window);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface CongressAlgorithm {
|
||||||
|
public void reset();
|
||||||
|
public void setWindowControlConsumer(Consumer<Long>windowControlConsumer);
|
||||||
|
public void setSpeedControlConsumer(BiConsumer<Long,Long>speedControlConsumer);
|
||||||
|
public void putAck(long packetSize,long latencyns,boolean ecn);
|
||||||
|
public void putLoss(long packetSize,long lossns,int losscounter);
|
||||||
|
public void setCurrentWindowUsed(long maxwindow);
|
||||||
|
public void setCurrentBandwidth(long bandwidth);
|
||||||
|
public long getRTO();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class ECNCongressAlgorithm implements CongressAlgorithm {
|
||||||
|
|
||||||
|
private static final long BURST_TIME = 2000000L;
|
||||||
|
private static final long BIAS = 2000000L;
|
||||||
|
private static long MIN_SPEED = 64 * 1024L;
|
||||||
|
private static long MIN_WINDOW = 16384;
|
||||||
|
|
||||||
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
private BiConsumer<Long, Long> speedControlConsumer;
|
||||||
|
|
||||||
|
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||||
|
private long MIN_RTTVAR = 50000000L;
|
||||||
|
private volatile long RTTMin = 1000000000L;
|
||||||
|
private volatile long RTTVar = 1000000000L;
|
||||||
|
private volatile long RTTAvg = 1000000000L;
|
||||||
|
private volatile long RTTAvg2 = 1000000000L;
|
||||||
|
private double ECNAvg2 = 0L;
|
||||||
|
private double alpha=0;
|
||||||
|
private volatile AtomicLong RTTTotal = new AtomicLong(0);
|
||||||
|
private volatile AtomicLong ECNSize = new AtomicLong(0);
|
||||||
|
private volatile AtomicLong TotalSize = new AtomicLong(0);
|
||||||
|
private volatile AtomicLong RTTCount = new AtomicLong(0);
|
||||||
|
private volatile long RTO = 1000000000L;
|
||||||
|
|
||||||
|
|
||||||
|
private volatile long window=MIN_WINDOW;
|
||||||
|
private volatile long windowUsed=MIN_WINDOW;
|
||||||
|
private volatile long congressWindowSize=MIN_WINDOW;
|
||||||
|
private volatile long speed=MIN_SPEED;
|
||||||
|
private long congressSpeed=MIN_SPEED;
|
||||||
|
|
||||||
|
private long RTTstartTime = System.nanoTime();
|
||||||
|
private long bandwidth=MIN_SPEED;
|
||||||
|
private double MAX_GAIN=1.2;//2.8853900817779
|
||||||
|
private double MIN_GAIN=1.2;
|
||||||
|
private double gain=MAX_GAIN;
|
||||||
|
|
||||||
|
private ReentrantLock lock=new ReentrantLock();
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
window = MIN_WINDOW;
|
||||||
|
if (windowControlConsumer != null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
speed = MIN_SPEED;
|
||||||
|
if (speedControlConsumer != null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
gain=MAX_GAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||||
|
this.windowControlConsumer = windowControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||||
|
this.speedControlConsumer = speedControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||||
|
if (latencyns <= RTTMin) {
|
||||||
|
RTTMin = latencyns;
|
||||||
|
} else {
|
||||||
|
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||||
|
}
|
||||||
|
if (firstUpdate.compareAndSet(true, false)) {
|
||||||
|
RTTAvg = latencyns;
|
||||||
|
RTTVar = latencyns / 2;
|
||||||
|
RTTAvg2 = latencyns;
|
||||||
|
} else {
|
||||||
|
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||||
|
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||||
|
}
|
||||||
|
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||||
|
|
||||||
|
RTTTotal .addAndGet( latencyns);
|
||||||
|
if(ecn) {
|
||||||
|
ECNSize.addAndGet(packetSize);
|
||||||
|
}
|
||||||
|
TotalSize.addAndGet(packetSize);
|
||||||
|
RTTCount.incrementAndGet();
|
||||||
|
|
||||||
|
|
||||||
|
long curr=System.nanoTime();
|
||||||
|
if(curr-RTTstartTime>RTTAvg2) {
|
||||||
|
RTTstartTime=curr;
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if(RTTCount.get()>0) {
|
||||||
|
long count=RTTCount.getAndSet(0);
|
||||||
|
RTTAvg2=RTTTotal.getAndSet(0)/count;
|
||||||
|
ECNAvg2=ECNSize.getAndSet(0)/(double)TotalSize.getAndSet(0);
|
||||||
|
alpha=(alpha*15+ECNAvg2)/16;
|
||||||
|
//System.out.println(alpha);
|
||||||
|
}
|
||||||
|
if(ECNAvg2>0.5) {
|
||||||
|
gain=MIN_GAIN;
|
||||||
|
if(congressWindowSize>MIN_WINDOW) {
|
||||||
|
congressWindowSize=Math.max(MIN_WINDOW,(long) (congressWindowSize*(1-alpha/5)));
|
||||||
|
updateWindowSize();
|
||||||
|
}
|
||||||
|
}else if(ECNAvg2>0.05){
|
||||||
|
if(windowUsed*3L>=congressWindowSize) {
|
||||||
|
congressWindowSize+=100;
|
||||||
|
updateWindowSize();
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if(windowUsed*3L>=congressWindowSize) {
|
||||||
|
congressWindowSize+=4000;
|
||||||
|
updateWindowSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bandwidth >= congressSpeed) {
|
||||||
|
congressSpeed = bandwidth;
|
||||||
|
} else {
|
||||||
|
congressSpeed = (congressSpeed * 99 + bandwidth) / 100;
|
||||||
|
}
|
||||||
|
speed=Math.max(MIN_SPEED,(long) (congressSpeed * gain)) ;
|
||||||
|
|
||||||
|
if (speedControlConsumer != null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//System.out.println(speed+" "+window);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateWindowSize() {
|
||||||
|
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.windowUsed=used;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentBandwidth(long bandwidth) {
|
||||||
|
this.bandwidth=bandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class EmptyCongressAlgorithm implements CongressAlgorithm{
|
||||||
|
|
||||||
|
private long timeout;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimeout() {
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentWindowUsed(long maxwindow) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentBandwidth(long bandwidth) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmptyCongressAlgorithm(long timeout) {
|
||||||
|
super();
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRTO() {
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class LARCCongressAlgorithm implements CongressAlgorithm {
|
||||||
|
|
||||||
|
private static final long BURST_TIME = 1000000L;
|
||||||
|
private static final long BIAS = 1000000L;
|
||||||
|
private static long MIN_SPEED = 64 * 1024L;
|
||||||
|
private static long MIN_WINDOW = 16384;
|
||||||
|
|
||||||
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
private BiConsumer<Long, Long> speedControlConsumer;
|
||||||
|
|
||||||
|
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||||
|
private long MIN_RTTVAR = 10000000L;
|
||||||
|
private volatile long RTTMin = 1000000000L;
|
||||||
|
private volatile long RTTVar = 1000000000L;
|
||||||
|
private volatile long RTTAvg = 1000000000L;
|
||||||
|
private volatile long RTTAvg2 = 1000000000L;
|
||||||
|
private volatile long RTTTotal = 0;
|
||||||
|
private volatile long RTTCount = 0;
|
||||||
|
private volatile long RTO = 1000000000L;
|
||||||
|
|
||||||
|
|
||||||
|
private volatile long window=MIN_WINDOW;
|
||||||
|
private volatile long speed=MIN_SPEED;
|
||||||
|
private volatile long maxwindow=99999999999L;
|
||||||
|
private long congressSpeed=MIN_SPEED;
|
||||||
|
private double MAX_GAIN=1.1;//2.8853900817779
|
||||||
|
private double MIN_GAIN=0.95;
|
||||||
|
private double windowGain=1.5;
|
||||||
|
private double speedGain=4;//MAX_GAIN
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
window = MIN_WINDOW;
|
||||||
|
if (windowControlConsumer != null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
speed = MIN_SPEED;
|
||||||
|
if (speedControlConsumer != null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
windowGain=MAX_GAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||||
|
this.windowControlConsumer = windowControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||||
|
this.speedControlConsumer = speedControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long RTTstartTime = System.nanoTime();
|
||||||
|
private long bandwidth;
|
||||||
|
@Override
|
||||||
|
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||||
|
if (latencyns <= RTTMin) {
|
||||||
|
RTTMin = latencyns;
|
||||||
|
} else {
|
||||||
|
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||||
|
}
|
||||||
|
if (firstUpdate.compareAndSet(true, false)) {
|
||||||
|
RTTAvg = latencyns;
|
||||||
|
RTTVar = latencyns / 2;
|
||||||
|
RTTAvg2 = latencyns;
|
||||||
|
} else {
|
||||||
|
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||||
|
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||||
|
}
|
||||||
|
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||||
|
|
||||||
|
RTTTotal += latencyns;
|
||||||
|
RTTCount++;
|
||||||
|
/*double rate=latencyns/(double)(RTTMin+BIAS);
|
||||||
|
if(rate>2) {
|
||||||
|
windowGain=MIN_GAIN;
|
||||||
|
}else if(rate<1.2){
|
||||||
|
windowGain=MAX_GAIN;
|
||||||
|
|
||||||
|
}*/
|
||||||
|
long curr=System.nanoTime();
|
||||||
|
if(curr-RTTstartTime>RTTAvg2) {
|
||||||
|
if(RTTCount>0) {
|
||||||
|
RTTAvg2=(RTTAvg2+RTTTotal/RTTCount)/2;
|
||||||
|
RTTTotal=0;
|
||||||
|
RTTCount=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTTstartTime=curr;
|
||||||
|
|
||||||
|
if (bandwidth >= congressSpeed) {
|
||||||
|
congressSpeed = bandwidth;
|
||||||
|
//congressSpeed = (congressSpeed + bandwidth) / 2;
|
||||||
|
} else {
|
||||||
|
congressSpeed = (congressSpeed * 199 + bandwidth) / 200;
|
||||||
|
}
|
||||||
|
speed=(long) (congressSpeed * speedGain)+MIN_SPEED ;
|
||||||
|
window= ((long) (congressSpeed*windowGain )*(RTTMin+BIAS)/1000000000L)+MIN_WINDOW;
|
||||||
|
if (windowControlConsumer != null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
if (speedControlConsumer != null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRTO() {
|
||||||
|
return RTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentWindowUsed(long used) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentBandwidth(long bandwidth) {
|
||||||
|
this.bandwidth=bandwidth;
|
||||||
|
|
||||||
|
//System.out.println(gain);
|
||||||
|
//System.out.println(bandwidth+" "+congressSpeed+" "+window);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络消息批量发送器,用于减少小包数量,降低网络性能开销
|
||||||
|
* @param <T> 消息类型
|
||||||
|
*/
|
||||||
|
public class MessageBatcher<T> implements Runnable{
|
||||||
|
private ArrayList<T> messageList;
|
||||||
|
private ReentrantLock lock=new ReentrantLock();
|
||||||
|
private final int batchSize;
|
||||||
|
private final long maxDelay;
|
||||||
|
private Consumer<List<T>> consumer;
|
||||||
|
private final Thread batchThread;
|
||||||
|
private final AtomicBoolean running;
|
||||||
|
private long firstTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param batchSize 批量大小,当消息达到此数量时触发发送
|
||||||
|
* @param maxDelayMillis 最大延迟时间(毫秒),即使消息数量不足也会触发发送
|
||||||
|
*/
|
||||||
|
public MessageBatcher(int batchSize, long maxDelay) {
|
||||||
|
this.batchSize = batchSize;
|
||||||
|
this.maxDelay = maxDelay;
|
||||||
|
this.running = new AtomicBoolean(true);
|
||||||
|
|
||||||
|
// 创建并启动批量处理线程
|
||||||
|
this.batchThread = new Thread(this);
|
||||||
|
this.batchThread.setDaemon(true);
|
||||||
|
this.batchThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置消息消费者回调函数
|
||||||
|
* @param consumer 消费者回调
|
||||||
|
*/
|
||||||
|
public void setConsumer(Consumer<List<T>> consumer) {
|
||||||
|
this.consumer = consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加消息到批量处理器
|
||||||
|
* @param message 消息对象
|
||||||
|
*/
|
||||||
|
public void putMessage(T message) {
|
||||||
|
if (message != null) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if(messageList==null) {
|
||||||
|
messageList=new ArrayList<T>(batchSize);
|
||||||
|
firstTime=System.nanoTime();
|
||||||
|
}
|
||||||
|
messageList.add(message);
|
||||||
|
check(false);
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量添加消息
|
||||||
|
* @param messages 消息列表
|
||||||
|
*/
|
||||||
|
public void putMessages(List<T> messages) {
|
||||||
|
for(T message :messages) {
|
||||||
|
putMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void check(boolean force) {
|
||||||
|
if(messageList==null)
|
||||||
|
return;
|
||||||
|
long currTime=System.nanoTime();
|
||||||
|
if(messageList.size()>=batchSize||(currTime-firstTime)>maxDelay||force) {
|
||||||
|
if(consumer!=null) {
|
||||||
|
try {
|
||||||
|
consumer.accept(messageList);
|
||||||
|
}catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
messageList=null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止批量处理器
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
running.set(false);
|
||||||
|
LockSupport.unpark(batchThread);
|
||||||
|
// 确保所有消息都被发送
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量处理消息的核心方法
|
||||||
|
*/
|
||||||
|
public void run() {
|
||||||
|
while(running.get()) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
check(false);
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
// 更精确的等待策略
|
||||||
|
long sleepTimeNanos = calculateSleepTime();
|
||||||
|
if (sleepTimeNanos > 0) {
|
||||||
|
LockSupport.parkNanos(sleepTimeNanos);
|
||||||
|
} else {
|
||||||
|
// 避免忙等待
|
||||||
|
LockSupport.parkNanos(1_000_000L); // 1ms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算需要等待的时间
|
||||||
|
* @return 等待时间(纳秒)
|
||||||
|
*/
|
||||||
|
private long calculateSleepTime() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if (messageList == null || messageList.isEmpty()) {
|
||||||
|
return 10_000_000L; // 10ms
|
||||||
|
}
|
||||||
|
|
||||||
|
long elapsed = System.nanoTime() - firstTime;
|
||||||
|
long remaining = maxDelay - elapsed;
|
||||||
|
|
||||||
|
if (remaining <= 0) {
|
||||||
|
return 0; // 立即处理
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回剩余时间或10ms中的较小值
|
||||||
|
return Math.min(remaining, 10_000_000L);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBatchSize() {
|
||||||
|
return batchSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxDelay() {
|
||||||
|
return maxDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
check(true);
|
||||||
|
}finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getQueueSize() {
|
||||||
|
List<T> cmessageList =messageList;
|
||||||
|
if(cmessageList==null)
|
||||||
|
return 0;
|
||||||
|
return cmessageList.size();
|
||||||
|
}
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
MessageBatcher<Integer>mes=new MessageBatcher<>(10, 1000000L);
|
||||||
|
mes.setConsumer((x)->{System.out.println(x);});
|
||||||
|
int n=0;
|
||||||
|
for(;;){
|
||||||
|
mes.putMessage(n++);
|
||||||
|
mes.putMessage(n++);
|
||||||
|
mes.putMessage(n++);
|
||||||
|
mes.putMessage(n++);
|
||||||
|
Thread.sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package org.kne.cloud.network.klalb;
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||||
|
|
||||||
public class ReceiveSlidingWindow<E> {
|
public class ReceiveByteSlidingWindow<E> {
|
||||||
private AtomicReferenceArray<E> array;
|
private AtomicReferenceArray<E> array;
|
||||||
private AtomicInteger windowSize =new AtomicInteger();
|
private AtomicInteger windowSize =new AtomicInteger();
|
||||||
private AtomicLong windowPosition=new AtomicLong();
|
private AtomicLong windowPosition=new AtomicLong();
|
||||||
@@ -26,7 +26,7 @@ public class ReceiveSlidingWindow<E> {
|
|||||||
this.windowPosition.set(windowPosition);
|
this.windowPosition.set(windowPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReceiveSlidingWindow(int capacity){
|
public ReceiveByteSlidingWindow(int capacity){
|
||||||
array=new AtomicReferenceArray<E>(capacity);
|
array=new AtomicReferenceArray<E>(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.kne.cloud.network.klalb;
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -6,7 +6,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||||
|
|
||||||
public class SendSlidingWindow<E> implements Iterable<E>{
|
public class SendByteSlidingWindow<E> implements Iterable<E>{
|
||||||
private Object[] array;
|
private Object[] array;
|
||||||
private volatile int windowSize ;
|
private volatile int windowSize ;
|
||||||
private volatile long windowPosition;
|
private volatile long windowPosition;
|
||||||
@@ -27,7 +27,7 @@ public class SendSlidingWindow<E> implements Iterable<E>{
|
|||||||
this.windowPosition=windowPosition;
|
this.windowPosition=windowPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SendSlidingWindow(int capacity,int windowSize){
|
public SendByteSlidingWindow(int capacity,int windowSize){
|
||||||
if(windowSize>capacity) {
|
if(windowSize>capacity) {
|
||||||
throw new IllegalArgumentException("windowSize>capacity!");
|
throw new IllegalArgumentException("windowSize>capacity!");
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
|
import org.kne.cloud.network.klalb.SendItem;
|
||||||
|
|
||||||
|
public class SendPacketSlidingWindow <K,V extends NetworkPacket> implements Closeable,AutoCloseable{
|
||||||
|
private Map<K,SendItem<V>> sendMap= new ConcurrentHashMap<>(1024,0.2f);
|
||||||
|
//private AtomicInteger sendmapWindowUsed=new AtomicInteger(0);
|
||||||
|
private LongAdder sendmapWindowUsed=new LongAdder();
|
||||||
|
|
||||||
|
private int headerCalibrate=0;
|
||||||
|
public void setHeaderCalibrate(int headerCalibrate) {
|
||||||
|
this.headerCalibrate = headerCalibrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CongressAlgorithm algorithm;
|
||||||
|
|
||||||
|
private Consumer<V> resendConsumer;
|
||||||
|
private Consumer<V> closingConsumer;
|
||||||
|
private volatile boolean closed=false;
|
||||||
|
private ResendChecker checker=new ResendChecker();
|
||||||
|
private AtomicLong windowSize = new AtomicLong();
|
||||||
|
|
||||||
|
|
||||||
|
private Lock lock;
|
||||||
|
|
||||||
|
private Condition condition;
|
||||||
|
|
||||||
|
public SendPacketSlidingWindow(CongressAlgorithm algorithm, long windowSize) {
|
||||||
|
super();
|
||||||
|
this.algorithm = algorithm;
|
||||||
|
this.windowSize .set( windowSize);
|
||||||
|
Thread t=new Thread(checker);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendPacketSlidingWindow(CongressAlgorithm algorithm, long windowSize,int headerCalibrate) {
|
||||||
|
this(algorithm,windowSize);
|
||||||
|
this.headerCalibrate=headerCalibrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getWindowSize() {
|
||||||
|
return windowSize.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWindowSize(long windowSize) {
|
||||||
|
this.windowSize.set(windowSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<V> getResendConsumer() {
|
||||||
|
return resendConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResendConsumer(Consumer<V> resendConsumer) {
|
||||||
|
this.resendConsumer = resendConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<V> getClosingConsumer() {
|
||||||
|
return closingConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClosingConsumer(Consumer<V> closingConsumer) {
|
||||||
|
this.closingConsumer = closingConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSendmapWindowUsed() {
|
||||||
|
return sendmapWindowUsed.sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeaderCalibrate() {
|
||||||
|
return headerCalibrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CongressAlgorithm getAlgorithm() {
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isCongress(IPv6Packet iPv6Packet,double scale) {
|
||||||
|
boolean congress=sendmapWindowUsed.sum()>windowSize.get()*scale;
|
||||||
|
return congress;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(K sequence,V packet) throws SocketException {
|
||||||
|
if(closed) {
|
||||||
|
throw new SocketException("sliding window closed!");
|
||||||
|
}
|
||||||
|
SendItem<V> newitem=new SendItem<V>( packet);
|
||||||
|
SendItem<V> old= sendMap.put(sequence,newitem);
|
||||||
|
if(old!=null) {
|
||||||
|
sendmapWindowUsed.add( -(old.getPacketLength()+headerCalibrate));
|
||||||
|
}
|
||||||
|
sendmapWindowUsed.add( (newitem.getPacketLength()+headerCalibrate));
|
||||||
|
long newWindow=sendmapWindowUsed.sum();
|
||||||
|
algorithm.setCurrentWindowUsed(newWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V ack(K sequence) {
|
||||||
|
SendItem<V> ipv6;
|
||||||
|
if((ipv6=sendMap.remove(sequence))!=null) {
|
||||||
|
sendmapWindowUsed.add( -(ipv6.getPacketLength()+headerCalibrate));
|
||||||
|
long newWindow= sendmapWindowUsed.sum();
|
||||||
|
algorithm.setCurrentWindowUsed(newWindow);
|
||||||
|
long RTTC=System.nanoTime()-ipv6.getSendtime();
|
||||||
|
algorithm.putAck(ipv6.getPacketLength(), RTTC, false);
|
||||||
|
//System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
||||||
|
Lock lockx=lock;
|
||||||
|
if(lockx!=null) {
|
||||||
|
lockx.lock();
|
||||||
|
try {
|
||||||
|
Condition cds=condition;
|
||||||
|
if(cds!=null) {
|
||||||
|
cds.signalAll();
|
||||||
|
}
|
||||||
|
}finally {
|
||||||
|
lockx.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ipv6.getPacket();
|
||||||
|
}else {
|
||||||
|
// System.out.println("miss:"+aseq.getSequence()+" "+sendMap.size());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ResendChecker implements Runnable{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while(!closed) {
|
||||||
|
|
||||||
|
Collection<SendItem<V>>vals= sendMap.values();
|
||||||
|
for (Iterator<SendItem<V>> iterator = vals.iterator(); iterator.hasNext();) {
|
||||||
|
SendItem<V> sitm = (SendItem<V>) iterator.next();
|
||||||
|
if(System.nanoTime() -sitm.getSendtime()>algorithm.getRTO()) {
|
||||||
|
iterator.remove();
|
||||||
|
sendmapWindowUsed.add((int) -(sitm.getPacketLength()+headerCalibrate));
|
||||||
|
long newWindow=sendmapWindowUsed.sum();
|
||||||
|
algorithm.setCurrentWindowUsed(newWindow);
|
||||||
|
//if(!kplink.isStream())
|
||||||
|
V pktr=sitm.getPacket();
|
||||||
|
pktr.setPriority(pktr.getPriority()-1);
|
||||||
|
if(resendConsumer!=null)
|
||||||
|
resendConsumer.accept(pktr);
|
||||||
|
//System.out.println("reroute");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(2);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 清理资源
|
||||||
|
if (closingConsumer != null) {
|
||||||
|
for (SendItem<V> item : sendMap.values()) {
|
||||||
|
closingConsumer.accept(item.getPacket());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendMap.clear();
|
||||||
|
sendmapWindowUsed.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
closed=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCongressCondition(Lock lock2, Condition condition2) {
|
||||||
|
this.lock=lock2;
|
||||||
|
this.condition=condition2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<K, SendItem<V>> getSendmap() {
|
||||||
|
return sendMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package org.kne.cloud.network.congress;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class VegasCongressAlgorithm implements CongressAlgorithm {
|
||||||
|
|
||||||
|
private static final long BURST_TIME = 1000000L;
|
||||||
|
private static final long BIAS = 1000000L;
|
||||||
|
private static long MIN_SPEED=256*1024L;
|
||||||
|
private static long MIN_WINDOW=4096L;
|
||||||
|
|
||||||
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
private BiConsumer<Long, Long> speedControlConsumer;
|
||||||
|
|
||||||
|
private AtomicBoolean firstUpdate=new AtomicBoolean(true);
|
||||||
|
private long MIN_RTTVAR=30000000L;
|
||||||
|
private volatile long RTTMin=1000000000L;
|
||||||
|
private volatile long RTTVar=1000000000L;
|
||||||
|
private volatile long RTTAvg=1000000000L;
|
||||||
|
private volatile long RTTAvg2=1000000000L;
|
||||||
|
private volatile long RTTTotal=0;
|
||||||
|
private volatile long RTTCount=0;
|
||||||
|
private volatile long RTO=1000000000L;
|
||||||
|
|
||||||
|
private volatile long window=MIN_WINDOW;
|
||||||
|
private volatile long speed=MIN_SPEED;
|
||||||
|
private volatile long maxwindow=99999999999L;
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
window=MIN_WINDOW;
|
||||||
|
if(windowControlConsumer!=null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
speed=MIN_SPEED;
|
||||||
|
if(speedControlConsumer!=null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||||
|
this.windowControlConsumer=windowControlConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||||
|
this.speedControlConsumer=speedControlConsumer;
|
||||||
|
}
|
||||||
|
private long RTTstartTime=System.nanoTime();
|
||||||
|
@Override
|
||||||
|
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||||
|
if(latencyns<=RTTMin) {
|
||||||
|
RTTMin=latencyns;
|
||||||
|
}else {
|
||||||
|
RTTMin= (RTTMin*9999+latencyns)/10000;
|
||||||
|
}
|
||||||
|
if(firstUpdate.compareAndSet(true, false)) {
|
||||||
|
RTTAvg=latencyns;
|
||||||
|
RTTVar=latencyns/2;
|
||||||
|
RTTAvg2=latencyns;
|
||||||
|
}else {
|
||||||
|
RTTVar=(RTTVar*3+Math.abs(RTTAvg-latencyns))/4;
|
||||||
|
RTTAvg= (RTTAvg*7+latencyns)/8;
|
||||||
|
}
|
||||||
|
RTO=RTTAvg+Math.max(MIN_RTTVAR, RTTVar*4);//RTTVar*4
|
||||||
|
|
||||||
|
RTTTotal+=latencyns;
|
||||||
|
RTTCount++;
|
||||||
|
|
||||||
|
long curr=System.nanoTime();
|
||||||
|
if(curr-RTTstartTime>RTTMin) {
|
||||||
|
if(RTTCount>0) {
|
||||||
|
RTTAvg2=(RTTAvg2+RTTTotal/RTTCount)/2;
|
||||||
|
RTTTotal=0;
|
||||||
|
RTTCount=0;
|
||||||
|
}
|
||||||
|
double excepted=window/(double)(Math.max( BIAS,RTTMin));
|
||||||
|
double actual=window/(double)(RTTAvg2);
|
||||||
|
double diff=(excepted-actual)*(Math.max( BIAS,RTTMin));
|
||||||
|
//System.out.println("diff:"+diff);
|
||||||
|
if(diff>65536*3) {
|
||||||
|
window-=512;
|
||||||
|
}
|
||||||
|
if(diff<65536*2) {
|
||||||
|
window+=512;
|
||||||
|
}
|
||||||
|
if(window>=maxwindow){
|
||||||
|
window=maxwindow;
|
||||||
|
//System.out.println("window:"+window);
|
||||||
|
}
|
||||||
|
if(window<MIN_WINDOW) {
|
||||||
|
window=MIN_WINDOW;
|
||||||
|
//System.out.println("window:"+window);
|
||||||
|
}
|
||||||
|
RTTstartTime=curr;
|
||||||
|
if(windowControlConsumer!=null) {
|
||||||
|
windowControlConsumer.accept(window);
|
||||||
|
}
|
||||||
|
speed=Math.max(MIN_SPEED, (long) (window/(double)(RTTAvg2)*1000000000.0*1.2));
|
||||||
|
if(speedControlConsumer!=null) {
|
||||||
|
speedControlConsumer.accept(speed, BURST_TIME);
|
||||||
|
}
|
||||||
|
//System.out.println(speed+" "+window);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRTO() {
|
||||||
|
return RTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentWindowUsed(long used) {
|
||||||
|
this.maxwindow=used*16+65536;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentBandwidth(long bandwidth) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.klalb.KLALBRemoteLine;
|
||||||
|
|
||||||
|
public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
||||||
|
private CopyOnWriteArraySet<IPv6LinkStateListener> listeners = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addIPv6LinkStateListener(IPv6LinkStateListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeIPv6LinkStateListener(IPv6LinkStateListener listener) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onOnlineStateUpdate() {
|
||||||
|
listeners.forEach((v) -> {
|
||||||
|
v.onOnlineStateUpdate(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public void onLocatorUpdate() {
|
||||||
|
listeners.forEach((v) -> {
|
||||||
|
v.onLocatorUpdate(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAddressUpdate() {
|
||||||
|
listeners.forEach((v) -> {
|
||||||
|
v.onAddressUpdate(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
|
import org.kne.io.KNEChannels;
|
||||||
|
|
||||||
|
public class ICMPv6EchoPacket extends ICMPv6Packet {
|
||||||
|
private static final int ECHO_HEADER_LENGTH = 4; // 标识符(2) + 序列号(2)
|
||||||
|
|
||||||
|
public ICMPv6EchoPacket(boolean isRequest,int sequenceNumber,int identifier) {
|
||||||
|
super(isRequest ? TYPE_ECHO_REQUEST : TYPE_ECHO_REPLY, 0);
|
||||||
|
setSequenceNumber(sequenceNumber);
|
||||||
|
setIdentifier(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取标识符
|
||||||
|
*/
|
||||||
|
public int getIdentifier() {
|
||||||
|
return getHeader().getChar(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置标识符
|
||||||
|
*/
|
||||||
|
public void setIdentifier(int identifier) {
|
||||||
|
getHeader().putChar(4, (char) identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取序列号
|
||||||
|
*/
|
||||||
|
public int getSequenceNumber() {
|
||||||
|
return getHeader().getChar(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置序列号
|
||||||
|
*/
|
||||||
|
public void setSequenceNumber(int sequenceNumber) {
|
||||||
|
getHeader().putChar(6, (char) sequenceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Ping请求包
|
||||||
|
*/
|
||||||
|
public static ICMPv6EchoPacket createPingRequest(int identifier, int sequenceNumber, byte[] payload) {
|
||||||
|
ICMPv6EchoPacket packet = new ICMPv6EchoPacket(true,identifier,sequenceNumber);
|
||||||
|
if (payload != null && payload.length > 0) {
|
||||||
|
packet.getData().put(payload);
|
||||||
|
packet.getData().flip();
|
||||||
|
}
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Ping回复包(基于请求包)
|
||||||
|
*/
|
||||||
|
public static ICMPv6EchoPacket createPingReply(ICMPv6EchoPacket request) {
|
||||||
|
ICMPv6EchoPacket reply = new ICMPv6EchoPacket(false,request.getIdentifier(),request.getSequenceNumber());
|
||||||
|
// 复制数据
|
||||||
|
if (request.getData() != null && request.getData().limit() > 0) {
|
||||||
|
ByteBuffer src = request.getData().duplicate();
|
||||||
|
src.position(0);
|
||||||
|
reply.getData().put(src);
|
||||||
|
reply.getData().flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String typeStr = getType() == TYPE_ECHO_REQUEST ? "Echo Request" : "Echo Reply";
|
||||||
|
return String.format("ICMPv6 %s [ID:%d, Seq:%d, Data:%d bytes]",
|
||||||
|
typeStr, getIdentifier(), getSequenceNumber(), getDataLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6Payload;
|
||||||
|
import org.kne.io.KNEChannels;
|
||||||
|
|
||||||
|
public class ICMPv6Packet extends IPv6Payload {
|
||||||
|
public static final int ICMPv6_PROTOCOL_NUMBER = 58;
|
||||||
|
public static final int ICMPv6_HEADER_LENGTH = 8; // ICMPv6基础头部固定8字节
|
||||||
|
|
||||||
|
// ICMPv6类型常量
|
||||||
|
public static final int TYPE_DESTINATION_UNREACHABLE = 1;
|
||||||
|
public static final int TYPE_PACKET_TOO_BIG = 2;
|
||||||
|
public static final int TYPE_TIME_EXCEEDED = 3;
|
||||||
|
public static final int TYPE_PARAMETER_PROBLEM = 4;
|
||||||
|
public static final int TYPE_ECHO_REQUEST = 128;
|
||||||
|
public static final int TYPE_ECHO_REPLY = 129;
|
||||||
|
|
||||||
|
private ByteBuffer header = NetworkPacket.bufferAllocator.allocate(ICMPv6_HEADER_LENGTH);
|
||||||
|
private ByteBuffer data;
|
||||||
|
|
||||||
|
public ICMPv6Packet() {
|
||||||
|
super(ICMPv6_PROTOCOL_NUMBER, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICMPv6Packet(int type, int code) {
|
||||||
|
super(ICMPv6_PROTOCOL_NUMBER, false);
|
||||||
|
getHeader().put((byte) type);
|
||||||
|
getHeader().put((byte) code);
|
||||||
|
// 校验和字段初始为0,后续计算
|
||||||
|
getHeader().putChar((char) 0);
|
||||||
|
data = NetworkPacket.bufferAllocator.allocate(65535);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTotalLength() {
|
||||||
|
return data != null ? data.limit() + ICMPv6_HEADER_LENGTH : ICMPv6_HEADER_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
||||||
|
// 写入头部和数据
|
||||||
|
dto.write(getHeader().slice(0, ICMPv6_HEADER_LENGTH));
|
||||||
|
if (data != null && data.limit() > 0) {
|
||||||
|
dto.write(data.slice(0, data.limit()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
||||||
|
// 读取ICMPv6头部
|
||||||
|
getHeader().clear().limit(ICMPv6_HEADER_LENGTH);
|
||||||
|
KNEChannels.readFully(din, getHeader());
|
||||||
|
|
||||||
|
// 读取数据部分(总长度减去头部长度)
|
||||||
|
long dataLength = length - ICMPv6_HEADER_LENGTH;
|
||||||
|
|
||||||
|
if (dataLength < 0) {
|
||||||
|
throw new IOException("Invalid ICMPv6 packet: total length < header length");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataLength > 0) {
|
||||||
|
data = NetworkPacket.bufferAllocator.allocate((int) dataLength);
|
||||||
|
KNEChannels.readFully(din, data);
|
||||||
|
data.flip();
|
||||||
|
} else {
|
||||||
|
data = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean needEndPosition() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ICMPv6类型
|
||||||
|
*/
|
||||||
|
public int getType() {
|
||||||
|
return getHeader().get(0) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置ICMPv6类型
|
||||||
|
*/
|
||||||
|
public void setType(int type) {
|
||||||
|
getHeader().put(0, (byte) type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ICMPv6代码
|
||||||
|
*/
|
||||||
|
public int getCode() {
|
||||||
|
return getHeader().get(1) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置ICMPv6代码
|
||||||
|
*/
|
||||||
|
public void setCode(int code) {
|
||||||
|
getHeader().put(1, (byte) code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取校验和
|
||||||
|
*/
|
||||||
|
public int getChecksum() {
|
||||||
|
return getHeader().getChar(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置校验和
|
||||||
|
*/
|
||||||
|
public void setChecksum(int checksum) {
|
||||||
|
getHeader().putChar(2, (char) checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取消息体(不同类型ICMPv6消息的特定字段)
|
||||||
|
* 对于Echo请求/回复,这是标识符和序列号
|
||||||
|
* 对于错误消息,这是未使用的字段和原始数据包片段
|
||||||
|
*/
|
||||||
|
public int getMessageBody() {
|
||||||
|
return getHeader().getInt(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置消息体
|
||||||
|
*/
|
||||||
|
public void setMessageBody(int messageBody) {
|
||||||
|
getHeader().putInt(4, messageBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数据部分长度
|
||||||
|
*/
|
||||||
|
public int getDataLength() {
|
||||||
|
return data != null ? data.limit() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算ICMPv6校验和
|
||||||
|
* ICMPv6校验和计算包括IPv6伪首部和整个ICMPv6报文
|
||||||
|
*/
|
||||||
|
public int calculateChecksum() {
|
||||||
|
if (getParent() == null) {
|
||||||
|
throw new IllegalStateException("Parent IPv6 packet required for checksum calculation");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存原始校验和值
|
||||||
|
int originalChecksum = getChecksum();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 临时将校验和字段设为0
|
||||||
|
setChecksum(0);
|
||||||
|
|
||||||
|
long sum = 0;
|
||||||
|
|
||||||
|
// IPv6伪首部
|
||||||
|
byte[] srcAddr = new byte[16], dstAddr = new byte[16];
|
||||||
|
getParent().getRawSourceAddress(srcAddr);
|
||||||
|
getParent().getRawDestinationAddress(dstAddr);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i += 2) {
|
||||||
|
sum += ((srcAddr[i] & 0xFF) << 8) | (srcAddr[i + 1] & 0xFF);
|
||||||
|
sum += ((dstAddr[i] & 0xFF) << 8) | (dstAddr[i + 1] & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICMPv6报文长度
|
||||||
|
int totalLength = (int) getTotalLength();
|
||||||
|
sum += (totalLength >>> 16) + totalLength;
|
||||||
|
sum += ICMPv6_PROTOCOL_NUMBER;
|
||||||
|
|
||||||
|
// ICMPv6头部
|
||||||
|
ByteBuffer headerCopy = getHeader().duplicate();
|
||||||
|
headerCopy.position(0).limit(ICMPv6_HEADER_LENGTH);
|
||||||
|
while (headerCopy.remaining() >= 2) {
|
||||||
|
sum += headerCopy.getChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICMPv6数据
|
||||||
|
if (data != null && data.limit() > 0) {
|
||||||
|
ByteBuffer dataCopy = data.duplicate();
|
||||||
|
dataCopy.position(0);
|
||||||
|
|
||||||
|
while (dataCopy.remaining() >= 2) {
|
||||||
|
sum += dataCopy.getChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataCopy.remaining() == 1) {
|
||||||
|
sum += (dataCopy.get() & 0xFF) << 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 折叠进位并取反
|
||||||
|
while ((sum >> 16) != 0) {
|
||||||
|
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
int checksum = (int) (~sum & 0xFFFF);
|
||||||
|
return checksum == 0 ? 0xFFFF : checksum;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 恢复原始校验和值
|
||||||
|
setChecksum(originalChecksum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新校验和
|
||||||
|
*/
|
||||||
|
public void updateChecksum() {
|
||||||
|
setChecksum(calculateChecksum());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证校验和
|
||||||
|
*/
|
||||||
|
public boolean verifyChecksum() {
|
||||||
|
int storedChecksum = getChecksum();
|
||||||
|
return storedChecksum == 0 || storedChecksum == calculateChecksum();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("ICMPv6 Type:").append(getType())
|
||||||
|
.append(" Code:").append(getCode())
|
||||||
|
.append(" [Total:").append(getTotalLength())
|
||||||
|
.append(", Data:").append(getDataLength()).append("]");
|
||||||
|
|
||||||
|
if (data != null && data.limit() > 0) {
|
||||||
|
byte[] b = new byte[Math.min(data.limit(), 10)];
|
||||||
|
data.get(0, b);
|
||||||
|
sb.append(" ").append(Arrays.toString(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 测试方法
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 创建一个Echo Request类型的ICMPv6包
|
||||||
|
ICMPv6Packet icmpv6 = new ICMPv6Packet(TYPE_ECHO_REQUEST, 0);
|
||||||
|
icmpv6.setMessageBody(0x12345678); // 设置标识符和序列号
|
||||||
|
|
||||||
|
// 添加一些测试数据
|
||||||
|
ByteBuffer testData = NetworkPacket.bufferAllocator.allocate(4);
|
||||||
|
testData.put("test".getBytes());
|
||||||
|
testData.flip();
|
||||||
|
icmpv6.data = testData;
|
||||||
|
|
||||||
|
// 创建父IPv6包(用于校验和计算)
|
||||||
|
IPv6Packet ipv6 = new IPv6Packet();
|
||||||
|
// 这里需要设置源和目的地址,但为了示例简化
|
||||||
|
|
||||||
|
icmpv6.setParent(ipv6);
|
||||||
|
|
||||||
|
System.out.println("Original checksum: " + icmpv6.calculateChecksum());
|
||||||
|
icmpv6.setChecksum(1);
|
||||||
|
System.out.println("Checksum verification (should be false): " + icmpv6.verifyChecksum());
|
||||||
|
icmpv6.updateChecksum();
|
||||||
|
System.out.println("Checksum verification (should be true): " + icmpv6.verifyChecksum());
|
||||||
|
System.out.println(icmpv6);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer getHeader() {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
import org.kne.io.KNEChannels;
|
||||||
|
|
||||||
|
public class ICMPv6TimeExceededPacket extends ICMPv6Packet {
|
||||||
|
private static final int UNUSED_FIELD_LENGTH = 4; // 未使用字段长度
|
||||||
|
|
||||||
|
// 代码值常量
|
||||||
|
public static final int CODE_HOP_LIMIT_EXCEEDED = 0; // 跳数限制超时
|
||||||
|
public static final int CODE_FRAGMENT_REASSEMBLY_EXCEEDED = 1; // 分片重组超时
|
||||||
|
|
||||||
|
public ICMPv6TimeExceededPacket(int code) {
|
||||||
|
super(TYPE_TIME_EXCEEDED, code);
|
||||||
|
setUnused(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取未使用字段(通常为0)
|
||||||
|
*/
|
||||||
|
public int getUnused() {
|
||||||
|
return getHeader().getInt(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置未使用字段(通常设为0)
|
||||||
|
*/
|
||||||
|
public void setUnused(int unused) {
|
||||||
|
getHeader().putInt(4, unused);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建跳数限制超时包
|
||||||
|
*/
|
||||||
|
public static ICMPv6TimeExceededPacket createHopLimitExceeded(IPv6Packet originalPacket) {
|
||||||
|
ICMPv6TimeExceededPacket packet = new ICMPv6TimeExceededPacket(CODE_HOP_LIMIT_EXCEEDED);
|
||||||
|
|
||||||
|
// 包含原始数据包的前缀(根据RFC,尽可能包含但不超出最小MTU)
|
||||||
|
if (originalPacket == null) {
|
||||||
|
throw new NullPointerException("originalPacket is null!");
|
||||||
|
}
|
||||||
|
// 这里简化处理,实际应该序列化原始包的前1280字节(IPv6最小MTU)
|
||||||
|
ByteBuffer buffer = NetworkPacket.bufferAllocator.allocate(65536);
|
||||||
|
buffer.clear();
|
||||||
|
try {
|
||||||
|
originalPacket.writeToChannel(KNEChannels.newWritableChannel(buffer));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
buffer.flip();
|
||||||
|
buffer.limit(Math.min(1280, buffer.limit()));
|
||||||
|
packet.getData().clear();
|
||||||
|
packet.getData().put(buffer);
|
||||||
|
packet.getData().flip();
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String codeStr = getCode() == CODE_HOP_LIMIT_EXCEEDED ?
|
||||||
|
"Hop Limit Exceeded" : "Fragment Reassembly Time Exceeded";
|
||||||
|
return String.format("ICMPv6 Time Exceeded [%s, OriginalPrefix:%d bytes]",
|
||||||
|
codeStr, getDataLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
|
||||||
|
public class IPv6HopByHopTLV extends TLV {
|
||||||
|
public static final int PAD1 = 0;
|
||||||
|
public static final int PADN = 1;
|
||||||
|
public static final int JUMBO_PAYLOAD = 0xC2;
|
||||||
|
public static final int ROUTER_ALERT = 0x05;
|
||||||
|
|
||||||
|
public IPv6HopByHopTLV(ByteBuffer header) {
|
||||||
|
this(header, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPv6HopByHopTLV(ByteBuffer header, boolean isDefault) {
|
||||||
|
super(header, isDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPv6HopByHopTLV(int type) {
|
||||||
|
this(type, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPv6HopByHopTLV(int type, boolean isDefault) {
|
||||||
|
super(type, isDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPv6HopByHopTLV readIPv6HopByHopTLVFromChannel(ReadableByteChannel din) throws IOException {
|
||||||
|
ByteBuffer bbf = NetworkPacket.bufferAllocator.allocate(2);
|
||||||
|
bbf.limit(1);
|
||||||
|
while (bbf.hasRemaining()) {
|
||||||
|
if (din.read(bbf) == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int type = bbf.get(0) & 0xff;
|
||||||
|
IPv6HopByHopTLV htlv;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case PAD1:
|
||||||
|
// Pad1: 只有类型字段,没有数据部分
|
||||||
|
htlv = new Pad1HopByHopTLV(bbf);
|
||||||
|
htlv.readFromChannel(din, 0);
|
||||||
|
return htlv;
|
||||||
|
case PADN:
|
||||||
|
// PadN: 有数据部分
|
||||||
|
htlv = new PadNHopByHopTLV(bbf);
|
||||||
|
htlv.readFromChannel(din, 0);
|
||||||
|
return htlv;
|
||||||
|
case ROUTER_ALERT:
|
||||||
|
// 路由器告警: 有数据部分
|
||||||
|
htlv = new RouterAlertHopByHopTLV(bbf, true);
|
||||||
|
htlv.readFromChannel(din, 0);
|
||||||
|
return htlv;
|
||||||
|
case JUMBO_PAYLOAD:
|
||||||
|
// 巨型载荷: 有数据部分
|
||||||
|
htlv = new JumboPayloadHopByHopTLV(bbf, true);
|
||||||
|
htlv.readFromChannel(din, 0);
|
||||||
|
return htlv;
|
||||||
|
default:
|
||||||
|
// 未知类型: 假设有数据部分
|
||||||
|
htlv = new IPv6HopByHopTLV(bbf, true);
|
||||||
|
htlv.readFromChannel(din, 0);
|
||||||
|
return htlv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeIPv6HopByHopTLVToChannel(WritableByteChannel dto, IPv6HopByHopTLV tlv) throws IOException {
|
||||||
|
tlv.writeToChannel(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "IPv6HopByHopTLV [getType()=" + getType() + ", getDataLength()=" + getDataLength() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 路由器告警 TLV - 有数据部分
|
||||||
|
*/
|
||||||
|
class RouterAlertHopByHopTLV extends IPv6HopByHopTLV {
|
||||||
|
public RouterAlertHopByHopTLV(ByteBuffer header, boolean isDefault) {
|
||||||
|
super(header, isDefault); // isDefault = true: 有数据部分
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getAlertValue() {
|
||||||
|
if (getData() != null && getData().remaining() >= 2) {
|
||||||
|
ByteBuffer duplicate = getData().duplicate();
|
||||||
|
return duplicate.getShort();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertValue(short value) {
|
||||||
|
if (getData() == null) {
|
||||||
|
// 根据isDefault逻辑,可能需要分配数据缓冲区
|
||||||
|
// 这里简化处理
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ByteBuffer duplicate = getData().duplicate();
|
||||||
|
duplicate.putShort(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巨型载荷 TLV - 有数据部分
|
||||||
|
*/
|
||||||
|
class JumboPayloadHopByHopTLV extends IPv6HopByHopTLV {
|
||||||
|
public JumboPayloadHopByHopTLV(ByteBuffer header, boolean isDefault) {
|
||||||
|
super(header, isDefault); // isDefault = true: 有数据部分
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getJumboLength() {
|
||||||
|
if (getData() != null && getData().remaining() >= 4) {
|
||||||
|
ByteBuffer duplicate = getData().duplicate();
|
||||||
|
return duplicate.getInt();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJumboLength(int length) {
|
||||||
|
if (getData() == null) return;
|
||||||
|
ByteBuffer duplicate = getData().duplicate();
|
||||||
|
duplicate.putInt(length);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
public interface IPv6LinkStateListener {
|
||||||
|
public void onOnlineStateUpdate(IPv6NetworkLink link);
|
||||||
|
public void onAddressUpdate(IPv6NetworkLink link);
|
||||||
|
public void onLocatorUpdate(IPv6NetworkLink link);
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package org.kne.cloud.network.ipv6;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
@@ -12,7 +14,7 @@ import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
|||||||
|
|
||||||
public interface IPv6NetworkLink {
|
public interface IPv6NetworkLink {
|
||||||
public boolean isLoopBack();
|
public boolean isLoopBack();
|
||||||
public Inet6AddressGroup getAddressGroup();
|
public List<Inet6AddressGroup> getAddressGroups();
|
||||||
public List<Neighbor> getNeighborsInfo();
|
public List<Neighbor> getNeighborsInfo();
|
||||||
public List<RouteItem> getRouteItems();
|
public List<RouteItem> getRouteItems();
|
||||||
public void sendPacket(IPv6Packet pack, Inet6Address inet6Address) throws IOException;
|
public void sendPacket(IPv6Packet pack, Inet6Address inet6Address) throws IOException;
|
||||||
@@ -22,8 +24,10 @@ public interface IPv6NetworkLink {
|
|||||||
}
|
}
|
||||||
public String getName();
|
public String getName();
|
||||||
public boolean isUp();
|
public boolean isUp();
|
||||||
public boolean canSend(IPv6Packet iPv6Packet);
|
|
||||||
public void setReceiveConsumer(Consumer<IPv6Packet>con);
|
public void setReceiveConsumer(Consumer<IPv6Packet>con);
|
||||||
void setRerouteConsumer(Consumer<IPv6Packet> rerouteConsumer);
|
void setRerouteConsumer(Consumer<IPv6Packet> rerouteConsumer);
|
||||||
public boolean isReachSpeedLimit(IPv6Packet iPv6Packet);
|
public boolean isReachSpeedLimit(IPv6Packet iPv6Packet);
|
||||||
|
public void setCongressCondition(Lock lock,Condition condition);
|
||||||
|
public void addIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||||
|
public void removeIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,305 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class IPv6RouteTableKey {
|
||||||
|
private long most;
|
||||||
|
private long least;
|
||||||
|
|
||||||
|
public IPv6RouteTableKey(byte[] address) {
|
||||||
|
long[] l = inet6AddressToLongs(address);
|
||||||
|
this.most = l[0];
|
||||||
|
this.least = l[1]; // 修复:应该是 l[1] 而不是 l[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPv6RouteTableKey(long most, long least) {
|
||||||
|
super();
|
||||||
|
this.most = most;
|
||||||
|
this.least = least;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPv6RouteTableKey(Inet6Address address) {
|
||||||
|
this(address.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPv6RouteTableKey(Inet6AddressGroup address) {
|
||||||
|
this(address.getAddress());
|
||||||
|
applyMask(address.getPrefixLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMost() {
|
||||||
|
return most;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLeast() {
|
||||||
|
return least;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + (int) (least ^ (least >>> 32));
|
||||||
|
result = prime * result + (int) (most ^ (most >>> 32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
IPv6RouteTableKey other = (IPv6RouteTableKey) obj;
|
||||||
|
if (least != other.least)
|
||||||
|
return false;
|
||||||
|
if (most != other.most)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据前缀长度应用掩码,仅保留网络部分
|
||||||
|
* @param prefixLength 前缀长度 (0-128)
|
||||||
|
* @return 应用掩码后的新 IPv6RouteTableKey 对象
|
||||||
|
*/
|
||||||
|
public IPv6RouteTableKey mask(int prefixLength) {
|
||||||
|
if (prefixLength < 0 || prefixLength > 128) {
|
||||||
|
throw new IllegalArgumentException("前缀长度必须在 0 到 128 之间");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefixLength == 0) {
|
||||||
|
return new IPv6RouteTableKey(0L, 0L); // 默认路由
|
||||||
|
}
|
||||||
|
|
||||||
|
long maskedMost = this.most;
|
||||||
|
long maskedLeast = this.least;
|
||||||
|
|
||||||
|
if (prefixLength <= 64) {
|
||||||
|
// 仅影响高位
|
||||||
|
long mask = createMask(prefixLength);
|
||||||
|
maskedMost &= mask;
|
||||||
|
maskedLeast = 0L; // 低位全部清零
|
||||||
|
} else {
|
||||||
|
// 影响高位和部分低位
|
||||||
|
int lowPrefixLength = prefixLength - 64;
|
||||||
|
long lowMask = createMask(lowPrefixLength);
|
||||||
|
maskedLeast &= lowMask;
|
||||||
|
// 高位保持不变
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IPv6RouteTableKey(maskedMost, maskedLeast);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据前缀长度应用掩码,仅保留网络部分
|
||||||
|
* @param prefixLength 前缀长度 (0-128)
|
||||||
|
* @return 应用掩码后的新 IPv6RouteTableKey 对象
|
||||||
|
*/
|
||||||
|
public void applyMask(int prefixLength) {
|
||||||
|
if (prefixLength < 0 || prefixLength > 128) {
|
||||||
|
throw new IllegalArgumentException("前缀长度必须在 0 到 128 之间");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefixLength == 0) {
|
||||||
|
this.most=0;
|
||||||
|
this.least=0;
|
||||||
|
return;
|
||||||
|
//return new IPv6RouteTableKey(0L, 0L); // 默认路由
|
||||||
|
}
|
||||||
|
|
||||||
|
long maskedMost = this.most;
|
||||||
|
long maskedLeast = this.least;
|
||||||
|
|
||||||
|
if (prefixLength <= 64) {
|
||||||
|
// 仅影响高位
|
||||||
|
long mask = createMask(prefixLength);
|
||||||
|
maskedMost &= mask;
|
||||||
|
maskedLeast = 0L; // 低位全部清零
|
||||||
|
} else {
|
||||||
|
// 影响高位和部分低位
|
||||||
|
int lowPrefixLength = prefixLength - 64;
|
||||||
|
long lowMask = createMask(lowPrefixLength);
|
||||||
|
maskedLeast &= lowMask;
|
||||||
|
// 高位保持不变
|
||||||
|
}
|
||||||
|
this.most=maskedMost;
|
||||||
|
this.least=maskedLeast;
|
||||||
|
// return new IPv6RouteTableKey(maskedMost, maskedLeast);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建指定长度的掩码
|
||||||
|
* @param bits 要保留的位数 (0-64)
|
||||||
|
* @return 掩码值
|
||||||
|
*/
|
||||||
|
private long createMask(int bits) {
|
||||||
|
// 使用查表法,预先计算所有可能的掩码值
|
||||||
|
return MASK_TABLE[bits];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预计算的掩码表
|
||||||
|
private static final long[] MASK_TABLE = new long[65]; // 0-64 共65个值
|
||||||
|
|
||||||
|
// 静态初始化块,在类加载时预计算所有掩码值
|
||||||
|
static {
|
||||||
|
for (int bits = 0; bits <= 64; bits++) {
|
||||||
|
if (bits == 0) {
|
||||||
|
MASK_TABLE[bits] = 0L;
|
||||||
|
} else if (bits == 64) {
|
||||||
|
MASK_TABLE[bits] = -1L;
|
||||||
|
} else {
|
||||||
|
MASK_TABLE[bits] = (-1L) << (64 - bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 byte[] 转换为两个 long 值(高位和低位)
|
||||||
|
* @param bytes 16字节的IPv6地址
|
||||||
|
* @return 包含两个long值的数组,第一个是高位,第二个是低位
|
||||||
|
*/
|
||||||
|
public static long[] inet6AddressToLongs(byte[] bytes) {
|
||||||
|
if (bytes.length != 16) {
|
||||||
|
throw new IllegalArgumentException("IPv6地址必须是16字节");
|
||||||
|
}
|
||||||
|
|
||||||
|
long high = 0;
|
||||||
|
long low = 0;
|
||||||
|
|
||||||
|
// 处理前8字节(高位)
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
high = (high << 8) | (bytes[i] & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理后8字节(低位)
|
||||||
|
for (int i = 8; i < 16; i++) {
|
||||||
|
low = (low << 8) | (bytes[i] & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new long[]{high, low};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将两个long值转换回byte[]
|
||||||
|
* @param high 高位long值
|
||||||
|
* @param low 低位long值
|
||||||
|
* @return 16字节的IPv6地址
|
||||||
|
*/
|
||||||
|
public static byte[] longsToInet6Address(long high, long low) {
|
||||||
|
byte[] bytes = new byte[16];
|
||||||
|
|
||||||
|
// 提取高位的8个字节
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
bytes[i] = (byte) ((high >> (56 - i * 8)) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取低位的8个字节
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
bytes[8 + i] = (byte) ((low >> (56 - i * 8)) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%016x:%016x", most, least);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单元测试
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
for(int i=0;i<65;i++) {
|
||||||
|
long l=MASK_TABLE[i];
|
||||||
|
System.out.println(Long.toUnsignedString(l, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("开始 IPv6RouteTableKey 单元测试...");
|
||||||
|
|
||||||
|
// 测试1: 基本转换测试
|
||||||
|
System.out.println("\n1. 测试基本转换:");
|
||||||
|
byte[] testAddress = new byte[16];
|
||||||
|
// 创建测试地址: 2001:0db8:85a3::8a2e:0370:7334
|
||||||
|
testAddress[0] = 0x20; testAddress[1] = 0x01;
|
||||||
|
testAddress[2] = 0x0d; testAddress[3] = (byte) 0xb8;
|
||||||
|
testAddress[4] = (byte) 0x85; testAddress[5] = (byte) 0xa3;
|
||||||
|
// 中间部分为0
|
||||||
|
testAddress[12] = (byte) 0x8a; testAddress[13] = 0x2e;
|
||||||
|
testAddress[14] = 0x03; testAddress[15] = 0x70;
|
||||||
|
// testAddress[16] = 0x73; testAddress[17] = 0x34; // 注意: 数组只有16个元素
|
||||||
|
|
||||||
|
IPv6RouteTableKey key = new IPv6RouteTableKey(testAddress);
|
||||||
|
System.out.println("原始地址: " + key);
|
||||||
|
|
||||||
|
// 测试2: 掩码应用测试
|
||||||
|
System.out.println("\n2. 测试掩码应用:");
|
||||||
|
IPv6RouteTableKey masked64 = key.mask(64);
|
||||||
|
System.out.println("/64 掩码: " + masked64);
|
||||||
|
|
||||||
|
IPv6RouteTableKey masked48 = key.mask(48);
|
||||||
|
System.out.println("/48 掩码: " + masked48);
|
||||||
|
|
||||||
|
IPv6RouteTableKey masked128 = key.mask(128);
|
||||||
|
System.out.println("/128 掩码: " + masked128);
|
||||||
|
|
||||||
|
IPv6RouteTableKey masked0 = key.mask(0);
|
||||||
|
System.out.println("/0 掩码: " + masked0);
|
||||||
|
|
||||||
|
// 测试3: 相等性测试
|
||||||
|
System.out.println("\n3. 测试相等性:");
|
||||||
|
IPv6RouteTableKey key2 = new IPv6RouteTableKey(testAddress);
|
||||||
|
System.out.println("相同地址是否相等: " + key.equals(key2));
|
||||||
|
System.out.println("哈希码是否相同: " + (key.hashCode() == key2.hashCode()));
|
||||||
|
|
||||||
|
// 测试4: 转换函数测试
|
||||||
|
System.out.println("\n4. 测试转换函数:");
|
||||||
|
long[] longs = inet6AddressToLongs(testAddress);
|
||||||
|
System.out.println("转换为longs: " + Long.toHexString(longs[0]) + ":" + Long.toHexString(longs[1]));
|
||||||
|
|
||||||
|
byte[] reconverted = longsToInet6Address(longs[0], longs[1]);
|
||||||
|
boolean conversionOk = true;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (testAddress[i] != reconverted[i]) {
|
||||||
|
conversionOk = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("转换是否可逆: " + conversionOk);
|
||||||
|
|
||||||
|
// 测试5: 边界条件测试
|
||||||
|
System.out.println("\n5. 测试边界条件:");
|
||||||
|
try {
|
||||||
|
key.applyMask(-1);
|
||||||
|
System.out.println("错误: 应该抛出异常");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
System.out.println("正确: 负前缀长度抛出异常");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
key.applyMask(129);
|
||||||
|
System.out.println("错误: 应该抛出异常");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
System.out.println("正确: 过大前缀长度抛出异常");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试6: 全零和全一地址测试
|
||||||
|
System.out.println("\n6. 测试特殊地址:");
|
||||||
|
byte[] allZeros = new byte[16];
|
||||||
|
IPv6RouteTableKey zeroKey = new IPv6RouteTableKey(allZeros);
|
||||||
|
System.out.println("全零地址: " + zeroKey);
|
||||||
|
|
||||||
|
byte[] allOnes = new byte[16];
|
||||||
|
for (int i = 0; i < 16; i++) allOnes[i] = (byte) 0xFF;
|
||||||
|
IPv6RouteTableKey onesKey = new IPv6RouteTableKey(allOnes);
|
||||||
|
System.out.println("全一地址: " + onesKey);
|
||||||
|
|
||||||
|
System.out.println("\n所有测试完成!");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,10 +11,12 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
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.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
@@ -40,7 +42,7 @@ import org.kne.concurrent.HighPerformanceExecutor;
|
|||||||
import org.kne.concurrent.SpinLock;
|
import org.kne.concurrent.SpinLock;
|
||||||
import org.kne.io.KNEChannels;
|
import org.kne.io.KNEChannels;
|
||||||
|
|
||||||
public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, AutoCloseable {
|
public class IPv6TUNLoopbackNetworkLink extends AbstractIPv6NetworkLink implements IPv6NetworkLink, Closeable, AutoCloseable {
|
||||||
|
|
||||||
public static final String KLALB_DECENTRALIZED_S_RV6_NETWORK = "KLALB Decentralized SRv6 Network";
|
public static final String KLALB_DECENTRALIZED_S_RV6_NETWORK = "KLALB Decentralized SRv6 Network";
|
||||||
|
|
||||||
@@ -76,7 +78,7 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
}
|
}
|
||||||
Thread tb = new Thread(() -> {
|
Thread tb = new Thread(() -> {
|
||||||
while (true) {
|
while (true) {
|
||||||
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocate(65535);
|
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocateNative(65535);
|
||||||
try {
|
try {
|
||||||
tun.read(tmp);
|
tun.read(tmp);
|
||||||
tmp.flip();
|
tmp.flip();
|
||||||
@@ -91,8 +93,8 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
//NetworkPacket.databufferpool_65535.back(tmp);
|
//NetworkPacket.databufferpool_65535.back(tmp);
|
||||||
if (con != null) {
|
if (con != null) {
|
||||||
|
|
||||||
monitor.getOutPacketCounterAL().incrementAndGet();
|
monitor.getOutPacketCounterAL().add(1);
|
||||||
monitor.getOutTrafficAL().addAndGet(ipp.getLength());
|
monitor.getOutTrafficAL().add(ipp.getTotalLength());
|
||||||
// ipp.setDisposeAfterSend(true);
|
// ipp.setDisposeAfterSend(true);
|
||||||
// ipp.getPayload().setDisposeAfterSend(true);
|
// ipp.getPayload().setDisposeAfterSend(true);
|
||||||
ipp.setPromise(true);
|
ipp.setPromise(true);
|
||||||
@@ -152,6 +154,7 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
}catch(UnsatisfiedLinkError e) {
|
}catch(UnsatisfiedLinkError e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
|
onOnlineStateUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkedBlockingQueue<ByteBuffer> sendQueue = new LinkedBlockingQueue<ByteBuffer>();
|
private LinkedBlockingQueue<ByteBuffer> sendQueue = new LinkedBlockingQueue<ByteBuffer>();
|
||||||
@@ -210,14 +213,15 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
SRv6PacketReorder newr= new SRv6PacketReorder(new PacketConsumer() {
|
SRv6PacketReorder newr= new SRv6PacketReorder(new PacketConsumer() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(IPv6Packet packx) throws IOException {
|
public boolean accept(IPv6Packet packx) throws IOException {
|
||||||
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocate(65535);
|
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocateNative(65535);
|
||||||
packx.writeToChannel(KNEChannels.newWritableChannel(tmp));
|
packx.writeToChannel(KNEChannels.newWritableChannel(tmp));
|
||||||
monitor.getInPacketCounterAL().incrementAndGet();
|
monitor.getInPacketCounterAL().add(1);
|
||||||
monitor.getInTrafficAL().addAndGet(packx.getLength());
|
monitor.getInTrafficAL().add(packx.getTotalLength());
|
||||||
tmp.flip();
|
tmp.flip();
|
||||||
sendQueue.add(tmp);
|
sendQueue.add(tmp);
|
||||||
LockSupport.unpark(tr);
|
LockSupport.unpark(tr);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
SRv6PacketReorder olr=reorder.putIfAbsent(fss,newr);
|
SRv6PacketReorder olr=reorder.putIfAbsent(fss,newr);
|
||||||
@@ -230,8 +234,8 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
}else {
|
}else {
|
||||||
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocate(65535);
|
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocate(65535);
|
||||||
pack.writeToChannel(KNEChannels.newWritableChannel(tmp));
|
pack.writeToChannel(KNEChannels.newWritableChannel(tmp));
|
||||||
monitor.getInPacketCounterAL().incrementAndGet();
|
monitor.getInPacketCounterAL().add(1);
|
||||||
monitor.getInTrafficAL().addAndGet(pack.getLength());
|
monitor.getInTrafficAL().add(pack.getTotalLength());
|
||||||
tmp.flip();
|
tmp.flip();
|
||||||
sendQueue.add(tmp);
|
sendQueue.add(tmp);
|
||||||
LockSupport.unpark(tr);
|
LockSupport.unpark(tr);
|
||||||
@@ -282,11 +286,7 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
tun.close();
|
tun.close();
|
||||||
tun = null;
|
tun = null;
|
||||||
}
|
}
|
||||||
}
|
onOnlineStateUpdate();
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canSend(IPv6Packet iPv6Packet) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -303,8 +303,8 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Inet6AddressGroup getAddressGroup() {
|
public List< Inet6AddressGroup> getAddressGroups() {
|
||||||
return hostAddress;
|
return List.of(hostAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -316,8 +316,10 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
public List<RouteItem> getRouteItems() {
|
public List<RouteItem> getRouteItems() {
|
||||||
List<RouteItem> rlist=new ArrayList<>();
|
List<RouteItem> rlist=new ArrayList<>();
|
||||||
|
|
||||||
rlist.add(new RouteItem(new Inet6AddressGroup(this.getAddressGroup().getAddress(), 128),
|
for(Inet6AddressGroup grp:getAddressGroups()) {
|
||||||
this.getAddressGroup().getAddress(), this, "Direct", 0, 1, null, "D",true));
|
rlist.add(new RouteItem(new Inet6AddressGroup(grp.getAddress(), 128),
|
||||||
|
grp.getAddress(), this, "Direct", 0, 1, null, "D",true));
|
||||||
|
}
|
||||||
|
|
||||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo()
|
for (Iterator<Neighbor> iteratorx = getNeighborsInfo()
|
||||||
.iterator(); iteratorx.hasNext();) {
|
.iterator(); iteratorx.hasNext();) {
|
||||||
@@ -339,4 +341,11 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCongressCondition(Lock lock, Condition condition) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.net.InetAddress;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class Inet6AddressGroup implements Comparable<Inet6AddressGroup>{
|
public class Inet6AddressGroup implements Comparable<Inet6AddressGroup>{
|
||||||
private static final byte[][] maskTransf=new byte[129][16];
|
private static final byte[][] maskTransf=new byte[129][16];
|
||||||
@@ -121,4 +122,21 @@ public class Inet6AddressGroup implements Comparable<Inet6AddressGroup>{
|
|||||||
prefixLength=in.read();
|
prefixLength=in.read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Inet6AddressGroup createPrefixOnlyAddressGroup(int newPrefixLength) {
|
||||||
|
byte[]mask=maskTransf[newPrefixLength];
|
||||||
|
byte[]andm=getAndm(mask);
|
||||||
|
try {
|
||||||
|
return new Inet6AddressGroup((Inet6Address) Inet6Address.getByAddress(andm), newPrefixLength);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Inet6AddressGroup createPrefixOnlyAddressGroup() {
|
||||||
|
return createPrefixOnlyAddressGroup(prefixLength);
|
||||||
|
}
|
||||||
|
public static void main(String[] args) throws UnknownHostException {
|
||||||
|
Inet6AddressGroup i6ag=new Inet6AddressGroup((Inet6Address) Inet6Address.getByName("1234:1234::1234"),12);
|
||||||
|
System.out.println(i6ag);
|
||||||
|
System.out.println(i6ag.createPrefixOnlyAddressGroup());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.srv6.PacketConsumer;
|
||||||
|
import org.kne.cloud.network.srv6.SRv6Router;
|
||||||
|
|
||||||
|
public class LoopbackIPv6NetworkLink extends AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
||||||
|
private IPv6NetworkLink fallbackLink;
|
||||||
|
|
||||||
|
|
||||||
|
public IPv6NetworkLink getFallbackLink() {
|
||||||
|
return fallbackLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFallbackLink(IPv6NetworkLink fallbackLink) {
|
||||||
|
this.fallbackLink = fallbackLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Integer, PacketConsumer> protocolNumberRegister = new ConcurrentHashMap<>(256 * 2);
|
||||||
|
|
||||||
|
public Map<Integer, PacketConsumer> getProtocolNumberRegister() {
|
||||||
|
return protocolNumberRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Inet6AddressGroup> addressGroups =new ArrayList<>();
|
||||||
|
|
||||||
|
//new Inet6AddressGroup(loopbackAddress, 128) new Inet6AddressGroup((Inet6Address) Inet6Address.getByName("::1"), 128)
|
||||||
|
public LoopbackIPv6NetworkLink(List<Inet6AddressGroup> addressGroupsx,SRv6Router router) {
|
||||||
|
this.addressGroups .addAll( addressGroupsx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<IPv6Packet> getReceiveConsumer() {
|
||||||
|
return receiveConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Consumer<IPv6Packet> receiveConsumer;
|
||||||
|
private Consumer<IPv6Packet> rerouteConsumer;
|
||||||
|
private SRv6Router router;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPacket(IPv6Packet pack, Inet6Address next) throws IOException {
|
||||||
|
PacketConsumer pcm= protocolNumberRegister.get(pack.getPayload().getProtocolNumber());
|
||||||
|
if (pcm != null) {
|
||||||
|
if(!pcm.accept(pack)) {
|
||||||
|
if(fallbackLink!=null) {
|
||||||
|
fallbackLink.sendPacket(pack, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if(fallbackLink!=null) {
|
||||||
|
fallbackLink.sendPacket(pack, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLoopBack() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Neighbor> getNeighborsInfo() {
|
||||||
|
List<Neighbor> hs = new ArrayList<>();
|
||||||
|
return hs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCongress(IPv6Packet iPv6Packet, double scale) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "inLoopBack";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUp() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReceiveConsumer(Consumer<IPv6Packet> con) {
|
||||||
|
this.receiveConsumer = con;
|
||||||
|
if(fallbackLink!=null) {
|
||||||
|
fallbackLink.setReceiveConsumer(con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Inet6AddressGroup> getAddressGroups() {
|
||||||
|
return addressGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRerouteConsumer(Consumer<IPv6Packet> rerouteConsumer) {
|
||||||
|
this.rerouteConsumer=rerouteConsumer;
|
||||||
|
if(fallbackLink!=null) {
|
||||||
|
fallbackLink.setRerouteConsumer(rerouteConsumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<IPv6Packet> getRerouteConsumer() {
|
||||||
|
return rerouteConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RouteItem> getRouteItems() {
|
||||||
|
List<RouteItem> rlist = new ArrayList<>();
|
||||||
|
for(Inet6AddressGroup group:addressGroups) {
|
||||||
|
rlist.add(new RouteItem(new Inet6AddressGroup(group.getAddress(), 128),
|
||||||
|
group.getAddress(), this, "Direct", 0, 0, null, "D", true));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
|
||||||
|
Neighbor addresses = (Neighbor) iteratorx.next();
|
||||||
|
RouteItem ri = new RouteItem(new Inet6AddressGroup(addresses.getAddress().getAddress(), 128),
|
||||||
|
addresses.getAddress().getAddress(), this, "Direct", 0, 128, addresses.getMonitor(), "D",
|
||||||
|
false);
|
||||||
|
rlist.add(ri);
|
||||||
|
|
||||||
|
RouteItem ris = new RouteItem(addresses.getLocator(),
|
||||||
|
(Inet6Address) addresses.getLocator().getAddress(), this, "KLALB SRv6", 13, 128,
|
||||||
|
addresses.getMonitor(), "D", false);
|
||||||
|
rlist.add(ris);
|
||||||
|
|
||||||
|
}
|
||||||
|
return rlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReachSpeedLimit(IPv6Packet iPv6Packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SRv6Router getRouter() {
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRouter(SRv6Router router) {
|
||||||
|
this.router = router;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCongressCondition(Lock lock, Condition condition) {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
@@ -32,9 +32,9 @@ public class Neighbor {
|
|||||||
this.locator = locator;
|
this.locator = locator;
|
||||||
this.monitor = monitor;
|
this.monitor = monitor;
|
||||||
}
|
}
|
||||||
public Neighbor(Inet6AddressGroup peerAddress, Inet6AddressGroup remoteVaddr, QueueingMonitorDataImpl monitor2,
|
public Neighbor(Inet6AddressGroup address, Inet6AddressGroup locator, MonitorData monitor2,
|
||||||
BandwidthDistributer<Inet6Address> bandwidthDistributer) {
|
BandwidthDistributer<Inet6Address> bandwidthDistributer) {
|
||||||
this(peerAddress,remoteVaddr,monitor2);
|
this(address,locator,monitor2);
|
||||||
this.bandwidthDistributer=bandwidthDistributer;
|
this.bandwidthDistributer=bandwidthDistributer;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.srv6.IPv6SegmentRoutingTLV;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pad1 Hop-by-Hop TLV - 没有数据部分
|
||||||
|
*/
|
||||||
|
public class Pad1HopByHopTLV extends IPv6HopByHopTLV {
|
||||||
|
public Pad1HopByHopTLV() {
|
||||||
|
super(IPv6HopByHopTLV.PAD1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pad1HopByHopTLV(ByteBuffer klalbHeader) {
|
||||||
|
super(klalbHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Pad1HopByHopTLV []";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.srv6.IPv6SegmentRoutingTLV;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PadN Hop-by-Hop TLV - 有数据部分
|
||||||
|
*/
|
||||||
|
public class PadNHopByHopTLV extends IPv6HopByHopTLV {
|
||||||
|
public PadNHopByHopTLV(ByteBuffer klalbHeader) {
|
||||||
|
super(klalbHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PadNHopByHopTLV(int dataLength) {
|
||||||
|
super(PadNHopByHopTLV.PADN);
|
||||||
|
getData().limit(dataLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PadNHopByHopTLV [getDataLength()=" + getDataLength() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 继承的readFromChannel和writeToChannel会正确处理数据部分
|
||||||
|
}
|
||||||
@@ -11,7 +11,32 @@ import org.kne.cloud.network.NetworkPacket;
|
|||||||
public class TLV extends NetworkPacket{
|
public class TLV extends NetworkPacket{
|
||||||
|
|
||||||
private int headerLength=2;
|
private int headerLength=2;
|
||||||
|
|
||||||
|
public static final int PAD1=0;
|
||||||
|
public TLV(ByteBuffer header, boolean isDefault) {
|
||||||
|
this.header=header;
|
||||||
|
this.isDefault=isDefault;
|
||||||
|
if(getType()==PAD1)
|
||||||
|
setHeaderLength(1);
|
||||||
|
if(isDefault&&(getHeaderLength()>1)) {
|
||||||
|
data=NetworkPacket.bufferAllocator.allocate(512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TLV(int type, boolean isDefault) {
|
||||||
|
if(type==PAD1) {
|
||||||
|
setHeaderLength(1);
|
||||||
|
}
|
||||||
|
this.header=NetworkPacket.bufferAllocator.allocate(getHeaderLength());
|
||||||
|
this.isDefault=isDefault;
|
||||||
|
header.put((byte) type);
|
||||||
|
header.put((byte) 0);
|
||||||
|
header.flip();
|
||||||
|
if(isDefault&&(getHeaderLength()>1)) {
|
||||||
|
data=NetworkPacket.bufferAllocator.allocate(512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int getHeaderLength() {
|
public int getHeaderLength() {
|
||||||
return headerLength;
|
return headerLength;
|
||||||
}
|
}
|
||||||
@@ -29,30 +54,31 @@ private int headerLength=2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLength() {
|
public long getTotalLength() {
|
||||||
return headerLength+(isDefault?data.limit():0);
|
return getHeaderLength()+(isDefault?data.limit():0);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
||||||
if(isDefault&&(headerLength>1)) {
|
if(isDefault&&(getHeaderLength()>1)) {
|
||||||
setDataLength(data.limit());
|
setDataLength(data.limit());
|
||||||
}
|
}
|
||||||
header.limit(headerLength);
|
header.limit(getHeaderLength());
|
||||||
dto.write(header.slice(0,header.limit()));
|
dto.write(header.slice(0,header.limit()));
|
||||||
if(isDefault&&(headerLength>1)) {
|
if(isDefault&&(getHeaderLength()>1)) {
|
||||||
dto.write(data.slice(0, data.limit()));
|
dto.write(data.slice(0, data.limit()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
||||||
|
|
||||||
header.limit(1);
|
header.limit(1);
|
||||||
while (header.hasRemaining()) {
|
while (header.hasRemaining()) {
|
||||||
if (din.read(header) == -1) {
|
if (din.read(header) == -1) {
|
||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(headerLength>1) {
|
if(getHeaderLength()>1) {
|
||||||
header.limit(2);
|
header.limit(2);
|
||||||
while (header.hasRemaining()) {
|
while (header.hasRemaining()) {
|
||||||
if (din.read(header) == -1) {
|
if (din.read(header) == -1) {
|
||||||
@@ -62,7 +88,7 @@ private int headerLength=2;
|
|||||||
}
|
}
|
||||||
header.flip();
|
header.flip();
|
||||||
|
|
||||||
if(isDefault&&(headerLength>1)) {
|
if(isDefault&&(getHeaderLength()>1)) {
|
||||||
data.clear();
|
data.clear();
|
||||||
data.limit(getDataLength());
|
data.limit(getDataLength());
|
||||||
while(data.hasRemaining()){
|
while(data.hasRemaining()){
|
||||||
@@ -93,4 +119,14 @@ private int headerLength=2;
|
|||||||
public void setDataLength(int dataLength) {
|
public void setDataLength(int dataLength) {
|
||||||
header.put(1,(byte) dataLength);
|
header.put(1,(byte) dataLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHeaderLength(int headerLength) {
|
||||||
|
this.headerLength = headerLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TLV [getType()=" + getType() + ", getDataLength()=" + getDataLength() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ public class ACKTPacket extends KLALBPacket implements PortPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ACKT "+getSport()+"->"+getDport()+" "+getNumber()+"[] avaliable:"+getAvaliableRcvWindow();
|
return "ACKT "+getSrcPort()+"->"+getDstPort()+" "+getNumber()+"[] avaliable:"+getAvaliableRcvWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSport() {
|
public int getSrcPort() {
|
||||||
return klalbHeader.getInt(1);
|
return klalbHeader.getInt(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public class ACKTPacket extends KLALBPacket implements PortPacket {
|
|||||||
return klalbHeader.get(26)!=0;
|
return klalbHeader.get(26)!=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDport() {
|
public int getDstPort() {
|
||||||
return klalbHeader.getInt(5);
|
return klalbHeader.getInt(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class ADDLINESPacket extends KLALBPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLength() {
|
public long getTotalLength() {
|
||||||
return HEADER_LENGTH+lines.getBytes(Charset.forName("UTF-8")).length;
|
return HEADER_LENGTH+lines.getBytes(Charset.forName("UTF-8")).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package org.kne.cloud.network.klalb;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
|
|
||||||
import org.kne.cloud.network.NetworkPacket;
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
import org.kne.io.KNEChannels;
|
import org.kne.io.KNEChannels;
|
||||||
@@ -19,76 +21,83 @@ public abstract class AbstractKLALBPacketLink implements KLALBPacketLink {
|
|||||||
AbstractKLALBPacketLink.defaultSoTimeout = defaultSoTimeout;
|
AbstractKLALBPacketLink.defaultSoTimeout = defaultSoTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AtomicLong[] inputTrafficCounters;
|
private LongAdder[] inputTrafficCounters;
|
||||||
private AtomicLong[] outputTrafficCounters;
|
private LongAdder[] outputTrafficCounters;
|
||||||
private AtomicLong[] inputPacketsCounters;
|
private LongAdder[] inputPacketsCounters;
|
||||||
private AtomicLong[] outputPacketsCounters;
|
private LongAdder[] outputPacketsCounters;
|
||||||
@Override
|
@Override
|
||||||
public void setOutputPacketsCounters(AtomicLong[] outCounter) {
|
public void setOutputPacketsCounters(LongAdder[] outCounter) {
|
||||||
outputPacketsCounters=outCounter;
|
outputPacketsCounters=outCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInputPacketsCounters(AtomicLong[] inCounter) {
|
public void setInputPacketsCounters(LongAdder[] inCounter) {
|
||||||
inputPacketsCounters=inCounter;
|
inputPacketsCounters=inCounter;
|
||||||
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setOutputTrafficCounters(AtomicLong[] outCounter) {
|
public void setOutputTrafficCounters(LongAdder[] outCounter) {
|
||||||
this.outputTrafficCounters=outCounter;
|
this.outputTrafficCounters=outCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInputTrafficCounters(AtomicLong[] inCounter) {
|
public void setInputTrafficCounters(LongAdder[] inCounter) {
|
||||||
this.inputTrafficCounters=inCounter;
|
this.inputTrafficCounters=inCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AtomicLong[] getInputTrafficCounters() {
|
public LongAdder[] getInputTrafficCounters() {
|
||||||
return inputTrafficCounters;
|
return inputTrafficCounters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AtomicLong[] getOutputTrafficCounters() {
|
public LongAdder[] getOutputTrafficCounters() {
|
||||||
return outputTrafficCounters;
|
return outputTrafficCounters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AtomicLong[] getInputPacketsCounters() {
|
public LongAdder[] getInputPacketsCounters() {
|
||||||
return inputPacketsCounters;
|
return inputPacketsCounters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AtomicLong[] getOutputPacketsCounters() {
|
public LongAdder[] getOutputPacketsCounters() {
|
||||||
return outputPacketsCounters;
|
return outputPacketsCounters;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void incOutput(int packetLength) {
|
protected void incOutput(int packetLength) {
|
||||||
if(outputTrafficCounters!=null) {
|
if(outputTrafficCounters!=null) {
|
||||||
for(AtomicLong al:outputTrafficCounters) {
|
for(LongAdder al:outputTrafficCounters) {
|
||||||
al.addAndGet(packetLength);
|
al.add(packetLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(outputPacketsCounters!=null) {
|
if(outputPacketsCounters!=null) {
|
||||||
for(AtomicLong al:outputPacketsCounters) {
|
for(LongAdder al:outputPacketsCounters) {
|
||||||
al.incrementAndGet();
|
al.add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void incInput(int packetLength) {
|
protected void incInput(int packetLength) {
|
||||||
if(inputTrafficCounters!=null) {
|
if(inputTrafficCounters!=null) {
|
||||||
for(AtomicLong al:inputTrafficCounters) {
|
for(LongAdder al:inputTrafficCounters) {
|
||||||
al.addAndGet(packetLength);
|
al.add(packetLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(inputPacketsCounters!=null) {
|
if(inputPacketsCounters!=null) {
|
||||||
for(AtomicLong al:inputPacketsCounters) {
|
for(LongAdder al:inputPacketsCounters) {
|
||||||
al.incrementAndGet();
|
al.add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeKLALBPackets(List<KLALBPacket> kps) throws IOException {
|
||||||
|
for(KLALBPacket pack:kps) {
|
||||||
|
writeKLALBPacket(pack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeKLALBPacket(KLALBPacket kp) throws IOException {
|
public void writeKLALBPacket(KLALBPacket kp) throws IOException {
|
||||||
ByteBuffer dataWrite=NetworkPacket.bufferAllocator.allocate((int) kp.getLength());
|
ByteBuffer dataWrite=NetworkPacket.bufferAllocator.allocate((int) kp.getTotalLength());
|
||||||
//dataWrite.clear();
|
dataWrite.clear();
|
||||||
KLALBPacket.writeKLALBPacketToChannel(KNEChannels.newWritableChannel( dataWrite), kp);
|
KLALBPacket.writeKLALBPacketToChannel(KNEChannels.newWritableChannel( dataWrite), kp);
|
||||||
dataWrite.flip();
|
dataWrite.flip();
|
||||||
writePacket(dataWrite);
|
writePacket(dataWrite);
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ public class BWINFPacket extends KLALBPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLength() {
|
public long getTotalLength() {
|
||||||
return super.getLength()+16;
|
return super.getTotalLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BWINFPacket(long upSpeed,long downSpeed) {
|
public BWINFPacket(long upSpeed,long downSpeed) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package org.kne.cloud.network.klalb;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
public interface BindableKLALBPacketConsumer extends KLALBPacketConsumer {
|
public interface BindableKLALBPacketConsumer extends PacketConsumer {
|
||||||
public InetAddress getRemoteInetAddress() ;
|
public InetAddress getRemoteInetAddress() ;
|
||||||
public InetAddress getLocalInetAddress() ;
|
public InetAddress getLocalInetAddress() ;
|
||||||
public int getPort() ;
|
public int getPort() ;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.kne.cloud.network.klalb;
|
|||||||
|
|
||||||
public class CONST {
|
public class CONST {
|
||||||
public static final String klalb="KLALB";
|
public static final String klalb="KLALB";
|
||||||
public static final String klalbver="3.2";
|
public static final String klalbver="3.4";
|
||||||
public static final int bversion=3;
|
public static final int bversion=3;
|
||||||
public static final int sversion=1;
|
public static final int sversion=1;
|
||||||
public static final int itemwidth = 720;
|
public static final int itemwidth = 720;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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 java.util.Arrays;
|
||||||
|
|
||||||
import org.kne.cloud.network.NetworkPacket;
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ public class DATATPacket extends KLALBPacket implements PortPacket{
|
|||||||
private static final int HEADER_LENGTH=20;
|
private static final int HEADER_LENGTH=20;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLength() {
|
public long getTotalLength() {
|
||||||
return HEADER_LENGTH+dataBuffer.limit();
|
return HEADER_LENGTH+dataBuffer.limit();
|
||||||
}
|
}
|
||||||
volatile long resendtimer=System.nanoTime();
|
volatile long resendtimer=System.nanoTime();
|
||||||
@@ -54,11 +55,11 @@ public class DATATPacket extends KLALBPacket implements PortPacket{
|
|||||||
super(bb,HEADER_LENGTH);
|
super(bb,HEADER_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSport() {
|
public int getSrcPort() {
|
||||||
return klalbHeader.getInt(1);
|
return klalbHeader.getInt(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDport() {
|
public int getDstPort() {
|
||||||
return klalbHeader.getInt(5);
|
return klalbHeader.getInt(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +76,9 @@ public class DATATPacket extends KLALBPacket implements PortPacket{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DATAT "+getSport()+"->"+getDport()+" "+getNumber()+"["+getSize()+"]";
|
byte[]b=new byte[Math.min(dataBuffer.limit(),10)];
|
||||||
|
dataBuffer.get(0, b);
|
||||||
|
return "DATAT "+getSrcPort()+"->"+getDstPort()+" "+getNumber()+"["+getSize()+"] "+Arrays.toString(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ public class IPSequence {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(uuid);
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
@@ -41,7 +44,12 @@ public class IPSequence {
|
|||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
IPSequence other = (IPSequence) obj;
|
IPSequence other = (IPSequence) obj;
|
||||||
return Objects.equals(uuid, other.uuid);
|
if (uuid == null) {
|
||||||
|
if (other.uuid != null)
|
||||||
|
return false;
|
||||||
|
} else if (!uuid.equals(other.uuid))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ public class IPv6OverKLALBPacket extends KLALBPacket {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLength() {
|
public long getTotalLength() {
|
||||||
return HEADER_LENGTH+ipv6Packet.getLength();
|
return HEADER_LENGTH+ipv6Packet.getTotalLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPv6Packet ipv6Packet;
|
private IPv6Packet ipv6Packet;
|
||||||
|
|
||||||
public IPv6OverKLALBPacket(IPv6Packet ipv6Packet) {
|
public IPv6OverKLALBPacket(IPv6Packet ipv6Packet) {
|
||||||
super(IPV6OVERKLALB,HEADER_LENGTH);
|
super(IPV6OVERKLALB,HEADER_LENGTH);
|
||||||
klalbHeader.putLong((int) ipv6Packet.getLength());
|
klalbHeader.putLong((int) ipv6Packet.getTotalLength());
|
||||||
this.ipv6Packet=ipv6Packet;
|
this.ipv6Packet=ipv6Packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,19 +41,28 @@ public class IPv6OverKLALBPacket extends KLALBPacket {
|
|||||||
return ipv6Packet;
|
return ipv6Packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/*@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "IPv6 "+ipv6Packet.getSourceAddress().getHostAddress()+"->"+ipv6Packet.getDestinationAddress().getHostAddress()+" type:"+ipv6Packet.getPayload().getProtocolNumber()+"["+getSize()+"]";
|
return "IPv6OverKLALBPacket "+ipv6Packet.getSourceAddress().getHostAddress()+"->"+ipv6Packet.getDestinationAddress().getHostAddress()+" type:"+ipv6Packet.getPayload().getProtocolNumber()+"["+getSize()+"]";
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
return ipv6Packet.getLength();
|
return ipv6Packet.getTotalLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "IPv6OverKLALBPacket [ipv6Packet=" + ipv6Packet + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
||||||
klalbHeader.putLong(1, ipv6Packet.getLength());
|
klalbHeader.putLong(1, ipv6Packet.getTotalLength());
|
||||||
super.writeToChannel(dto);
|
super.writeToChannel(dto);
|
||||||
ipv6Packet.writeToChannel(dto);
|
ipv6Packet.writeToChannel(dto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import java.io.FileNotFoundException;
|
|||||||
|
|
||||||
public class KLALBConfig extends ArrayList<KLALBConfigItem>{
|
public class KLALBConfig extends ArrayList<KLALBConfigItem>{
|
||||||
public static void main(String[] args) throws UnknownHostException, JsonSyntaxException, JsonIOException, FileNotFoundException {
|
public static void main(String[] args) throws UnknownHostException, JsonSyntaxException, JsonIOException, FileNotFoundException {
|
||||||
GsonBuilder gb=new GsonBuilder();
|
GsonBuilder gb=new GsonBuilder().setPrettyPrinting();
|
||||||
MultipurposeSocketAddress.registerToGsonBuilder(gb);
|
MultipurposeSocketAddress.registerToGsonBuilder(gb);
|
||||||
KLALBConfigItem.registerToGsonBuilder(gb);
|
KLALBConfigItem.registerToGsonBuilder(gb);
|
||||||
Gson gson=gb.create();
|
Gson gson=gb.create();
|
||||||
|
|||||||
@@ -22,9 +22,17 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
private String VirtualSocketName;
|
private String VirtualSocketName;
|
||||||
private List<MultipurposeSocketAddress>LineTable=new ArrayList<>();
|
private List<MultipurposeSocketAddress>LineTable=new ArrayList<>();
|
||||||
private List<MultipurposeSocketAddress>ConnectLineTable=new ArrayList<>();
|
private List<MultipurposeSocketAddress>ConnectLineTable=new ArrayList<>();
|
||||||
|
private List<MultipurposeSocketAddress>ntpServerTable=new ArrayList<>();
|
||||||
|
public void setNetworkInterfaceExcepts(List<String> networkInterfaceExcepts) {
|
||||||
|
NetworkInterfaceExcepts = networkInterfaceExcepts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private List<String>NetworkInterfaceExcepts=new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public KLALBControllerConfigItem(String type, boolean nogui, String virtualAddress, Long virtualASN,
|
public KLALBControllerConfigItem(String type, boolean nogui, String virtualAddress, Long virtualASN,
|
||||||
List<InetAddress> dNS, MultipurposeSocketAddress tCPListen, MultipurposeSocketAddress uDPListen,
|
List<InetAddress> dNS, MultipurposeSocketAddress tCPListen, MultipurposeSocketAddress uDPListen,
|
||||||
@@ -43,6 +51,12 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public List<String> getNetworkInterfaceExcepts() {
|
||||||
|
return NetworkInterfaceExcepts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setLanguage(String language) {
|
public void setLanguage(String language) {
|
||||||
this.language = language;
|
this.language = language;
|
||||||
@@ -170,12 +184,27 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public List<MultipurposeSocketAddress> getNtpServerTable() {
|
||||||
|
return ntpServerTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void setNtpServerTable(List<MultipurposeSocketAddress> ntpServerTable) {
|
||||||
|
this.ntpServerTable = ntpServerTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "KLALBControllerConfigItem [language=" + language + ", nogui=" + nogui + ", VirtualAddress="
|
return "KLALBControllerConfigItem [language=" + language + ", nogui=" + nogui + ", VirtualAddress="
|
||||||
+ VirtualAddress + ", VirtualASN=" + VirtualASN + ", DNS=" + DNS + ", TCPListen=" + TCPListen
|
+ VirtualAddress + ", VirtualASN=" + VirtualASN + ", DNS=" + DNS + ", TCPListen=" + TCPListen
|
||||||
+ ", UDPListen=" + UDPListen + ", VirtualSocketName=" + VirtualSocketName + ", LineTable=" + LineTable
|
+ ", UDPListen=" + UDPListen + ", VirtualSocketName=" + VirtualSocketName + ", LineTable=" + LineTable
|
||||||
+ ", ConnectLineTable=" + ConnectLineTable + "]";
|
+ ", ConnectLineTable=" + ConnectLineTable + ", ntpServerTable=" + ntpServerTable
|
||||||
|
+ ", NetworkInterfaceExcepts=" + NetworkInterfaceExcepts + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -184,8 +213,18 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = super.hashCode();
|
int result = super.hashCode();
|
||||||
result = prime * result + Objects.hash(ConnectLineTable, DNS, LineTable, TCPListen, UDPListen, VirtualASN,
|
result = prime * result + ((ConnectLineTable == null) ? 0 : ConnectLineTable.hashCode());
|
||||||
VirtualAddress, VirtualSocketName, language, nogui);
|
result = prime * result + ((DNS == null) ? 0 : DNS.hashCode());
|
||||||
|
result = prime * result + ((LineTable == null) ? 0 : LineTable.hashCode());
|
||||||
|
result = prime * result + ((NetworkInterfaceExcepts == null) ? 0 : NetworkInterfaceExcepts.hashCode());
|
||||||
|
result = prime * result + ((TCPListen == null) ? 0 : TCPListen.hashCode());
|
||||||
|
result = prime * result + ((UDPListen == null) ? 0 : UDPListen.hashCode());
|
||||||
|
result = prime * result + ((VirtualASN == null) ? 0 : VirtualASN.hashCode());
|
||||||
|
result = prime * result + ((VirtualAddress == null) ? 0 : VirtualAddress.hashCode());
|
||||||
|
result = prime * result + ((VirtualSocketName == null) ? 0 : VirtualSocketName.hashCode());
|
||||||
|
result = prime * result + ((language == null) ? 0 : language.hashCode());
|
||||||
|
result = prime * result + (nogui ? 1231 : 1237);
|
||||||
|
result = prime * result + ((ntpServerTable == null) ? 0 : ntpServerTable.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,12 +239,64 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
KLALBControllerConfigItem other = (KLALBControllerConfigItem) obj;
|
KLALBControllerConfigItem other = (KLALBControllerConfigItem) obj;
|
||||||
return Objects.equals(ConnectLineTable, other.ConnectLineTable) && Objects.equals(DNS, other.DNS)
|
if (ConnectLineTable == null) {
|
||||||
&& Objects.equals(LineTable, other.LineTable) && Objects.equals(TCPListen, other.TCPListen)
|
if (other.ConnectLineTable != null)
|
||||||
&& Objects.equals(UDPListen, other.UDPListen) && Objects.equals(VirtualASN, other.VirtualASN)
|
return false;
|
||||||
&& Objects.equals(VirtualAddress, other.VirtualAddress)
|
} else if (!ConnectLineTable.equals(other.ConnectLineTable))
|
||||||
&& Objects.equals(VirtualSocketName, other.VirtualSocketName)
|
return false;
|
||||||
&& Objects.equals(language, other.language) && nogui == other.nogui;
|
if (DNS == null) {
|
||||||
|
if (other.DNS != null)
|
||||||
|
return false;
|
||||||
|
} else if (!DNS.equals(other.DNS))
|
||||||
|
return false;
|
||||||
|
if (LineTable == null) {
|
||||||
|
if (other.LineTable != null)
|
||||||
|
return false;
|
||||||
|
} else if (!LineTable.equals(other.LineTable))
|
||||||
|
return false;
|
||||||
|
if (NetworkInterfaceExcepts == null) {
|
||||||
|
if (other.NetworkInterfaceExcepts != null)
|
||||||
|
return false;
|
||||||
|
} else if (!NetworkInterfaceExcepts.equals(other.NetworkInterfaceExcepts))
|
||||||
|
return false;
|
||||||
|
if (TCPListen == null) {
|
||||||
|
if (other.TCPListen != null)
|
||||||
|
return false;
|
||||||
|
} else if (!TCPListen.equals(other.TCPListen))
|
||||||
|
return false;
|
||||||
|
if (UDPListen == null) {
|
||||||
|
if (other.UDPListen != null)
|
||||||
|
return false;
|
||||||
|
} else if (!UDPListen.equals(other.UDPListen))
|
||||||
|
return false;
|
||||||
|
if (VirtualASN == null) {
|
||||||
|
if (other.VirtualASN != null)
|
||||||
|
return false;
|
||||||
|
} else if (!VirtualASN.equals(other.VirtualASN))
|
||||||
|
return false;
|
||||||
|
if (VirtualAddress == null) {
|
||||||
|
if (other.VirtualAddress != null)
|
||||||
|
return false;
|
||||||
|
} else if (!VirtualAddress.equals(other.VirtualAddress))
|
||||||
|
return false;
|
||||||
|
if (VirtualSocketName == null) {
|
||||||
|
if (other.VirtualSocketName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!VirtualSocketName.equals(other.VirtualSocketName))
|
||||||
|
return false;
|
||||||
|
if (language == null) {
|
||||||
|
if (other.language != null)
|
||||||
|
return false;
|
||||||
|
} else if (!language.equals(other.language))
|
||||||
|
return false;
|
||||||
|
if (nogui != other.nogui)
|
||||||
|
return false;
|
||||||
|
if (ntpServerTable == null) {
|
||||||
|
if (other.ntpServerTable != null)
|
||||||
|
return false;
|
||||||
|
} else if (!ntpServerTable.equals(other.ntpServerTable))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import javax.swing.JFrame;
|
|||||||
import org.kne.cloud.network.MultipurposeSocketAddress;
|
import org.kne.cloud.network.MultipurposeSocketAddress;
|
||||||
import org.kne.cloud.network.SocketChannelListener;
|
import org.kne.cloud.network.SocketChannelListener;
|
||||||
import org.kne.cloud.network.SocketListener;
|
import org.kne.cloud.network.SocketListener;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
|
||||||
import org.kne.cloud.network.ipv6.RouteItem;
|
import org.kne.cloud.network.ipv6.RouteItem;
|
||||||
import org.kne.cloud.network.klalb.ui.KLALBStateGUI2;
|
import org.kne.cloud.network.klalb.ui.KLALBStateGUI2;
|
||||||
import org.kne.cloud.network.klalb.ui.KLALBStateGUI3;
|
import org.kne.cloud.network.klalb.ui.KLALBStateGUI3;
|
||||||
@@ -25,6 +26,7 @@ import org.kne.cloud.network.perf.Kperf;
|
|||||||
import org.kne.cloud.network.perf.MemcpyBenchmark;
|
import org.kne.cloud.network.perf.MemcpyBenchmark;
|
||||||
import org.kne.cloud.network.perf.NodeBenchmark;
|
import org.kne.cloud.network.perf.NodeBenchmark;
|
||||||
import org.kne.debug.Debuger;
|
import org.kne.debug.Debuger;
|
||||||
|
import org.kne.debug.TimeDebugger;
|
||||||
|
|
||||||
public class KLALBMain {
|
public class KLALBMain {
|
||||||
public static KLALBStateGUI3 ksg;
|
public static KLALBStateGUI3 ksg;
|
||||||
@@ -36,18 +38,23 @@ public class KLALBMain {
|
|||||||
}
|
}
|
||||||
System.out.println(CONST.klalb+" V"+CONST.klalbver);
|
System.out.println(CONST.klalb+" V"+CONST.klalbver);
|
||||||
Scanner scn=new Scanner(System.in);
|
Scanner scn=new Scanner(System.in);
|
||||||
|
TimeDebugger dtb=new TimeDebugger();
|
||||||
|
dtb.putTime("Start");
|
||||||
File configJson=new File("klalb-config.json");
|
File configJson=new File("klalb-config.json");
|
||||||
|
|
||||||
KLALBProxySystem kpcje=new KLALBProxySystem();
|
KLALBProxySystem kpcje=new KLALBProxySystem();
|
||||||
|
dtb.putTime("Create");
|
||||||
kpcje.loadConfigJson(configJson);
|
kpcje.loadConfigJson(configJson);
|
||||||
|
dtb.putTime("Load");
|
||||||
System.out.println("SRv6地址:"+kpcje.getKlalbController().getSelf().getAddress().getHostAddress());
|
System.out.println("SRv6地址:"+kpcje.getKlalbController().getSelf().getAddress().getHostAddress());
|
||||||
try {
|
try {
|
||||||
if(!kpcje.getControllerConfig().isNogui())
|
if(!kpcje.getControllerConfig().isNogui())
|
||||||
openGUI(kpcje);
|
openGUI(kpcje);
|
||||||
}catch(Throwable e) {
|
}catch(Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
dtb.putTime("UI");
|
||||||
|
//dtb.print();
|
||||||
/*MultipurposeSocketAddress mpa=new MultipurposeSocketAddress("127.9.9.9", 49573);
|
/*MultipurposeSocketAddress mpa=new MultipurposeSocketAddress("127.9.9.9", 49573);
|
||||||
kpcje.enableRemoteManagement(mpa);
|
kpcje.enableRemoteManagement(mpa);
|
||||||
System.out.println("远程管理端口已在"+mpa+"端口上开启");*/
|
System.out.println("远程管理端口已在"+mpa+"端口上开启");*/
|
||||||
@@ -58,7 +65,7 @@ public class KLALBMain {
|
|||||||
SocketChannelListener stlr=new SocketChannelListener(kpsvr);
|
SocketChannelListener stlr=new SocketChannelListener(kpsvr);
|
||||||
stlr.setCon((scl)->{
|
stlr.setCon((scl)->{
|
||||||
try {
|
try {
|
||||||
new Kperf(new StreamChannelKLALBPacketLink(scl)).startPerfing();
|
new Kperf(new StreamChannelKLALBPacketLink(scl,false)).startPerfing();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -92,10 +99,12 @@ public class KLALBMain {
|
|||||||
System.out.println("线路状态:");
|
System.out.println("线路状态:");
|
||||||
System.out.println("状态\t上传流量\t下载流量\t上传速度\t下载速度\t上传延迟\t下载延迟\t上传抖动\t下载抖动");
|
System.out.println("状态\t上传流量\t下载流量\t上传速度\t下载速度\t上传延迟\t下载延迟\t上传抖动\t下载抖动");
|
||||||
synchronized (kpcje.getKlalbController().getLines()) {
|
synchronized (kpcje.getKlalbController().getLines()) {
|
||||||
for (Iterator<KLALBRemoteLine> iterator = kpcje.getKlalbController().getLines().iterator(); iterator.hasNext();) {
|
for (Iterator<IPv6NetworkLink> iterator = kpcje.getKlalbController().getLines().iterator(); iterator.hasNext();) {
|
||||||
KLALBRemoteLine hostPort = iterator.next();
|
IPv6NetworkLink link=iterator.next();
|
||||||
|
if(link instanceof KLALBRemoteLine) {
|
||||||
|
KLALBRemoteLine hostPort = (KLALBRemoteLine) link;
|
||||||
System.out.println(hostPort .toString());
|
System.out.println(hostPort .toString());
|
||||||
//System.out.println();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -209,13 +218,13 @@ public class KLALBMain {
|
|||||||
|
|
||||||
}
|
}
|
||||||
private static void openGUI(KLALBProxySystem kpcje) throws RuntimeException{
|
private static void openGUI(KLALBProxySystem kpcje) throws RuntimeException{
|
||||||
/*JFrame jf=new JFrame();
|
Thread t=new Thread(()->{
|
||||||
jf.setSize(200, 200);
|
if(ksg==null) {
|
||||||
jf.setVisible(true);*/
|
|
||||||
if(ksg==null)
|
|
||||||
ksg=kpcje.getKLALBGUI();
|
ksg=kpcje.getKLALBGUI();
|
||||||
|
}
|
||||||
ksg.setVisible(true);
|
ksg.setVisible(true);
|
||||||
//System.out.println("UI loaded");
|
});
|
||||||
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public class KLALBOutputStream extends DataOutputStream {
|
|||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
public void writeKLALBPacket(KLALBPacket klb) throws IOException {
|
public void writeKLALBPacket(KLALBPacket klb) throws IOException {
|
||||||
writeInt((int) klb.getLength());
|
writeInt((int) klb.getTotalLength());
|
||||||
KLALBPacket.writeKLALBPacketToStream(this, klb);
|
KLALBPacket.writeKLALBPacketToStream(this, klb);
|
||||||
}
|
}
|
||||||
public void writePacket(ByteBuffer kp) throws IOException {
|
public void writePacket(ByteBuffer kp) throws IOException {
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public abstract class KLALBPacket extends IPv6Packet.IPv6Payload {
|
|||||||
public long getRcvtime() {
|
public long getRcvtime() {
|
||||||
return rcvtime;
|
return rcvtime;
|
||||||
}
|
}
|
||||||
public long getLength() {//缓冲区limit,实际长度
|
public long getTotalLength() {//缓冲区limit,实际长度
|
||||||
return headerLength;
|
return headerLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +147,7 @@ public abstract class KLALBPacket extends IPv6Packet.IPv6Payload {
|
|||||||
public static KLALBPacket readKLALBPacketFromChannel(ReadableByteChannel in) throws IOException {
|
public static KLALBPacket readKLALBPacketFromChannel(ReadableByteChannel in) throws IOException {
|
||||||
while(true) {
|
while(true) {
|
||||||
ByteBuffer bb=NetworkPacket.bufferAllocator.allocate(40);
|
ByteBuffer bb=NetworkPacket.bufferAllocator.allocate(40);
|
||||||
|
bb.position(0);
|
||||||
bb.limit(1);
|
bb.limit(1);
|
||||||
while(bb.hasRemaining()){
|
while(bb.hasRemaining()){
|
||||||
if(in.read(bb)==-1) {
|
if(in.read(bb)==-1) {
|
||||||
|
|||||||
@@ -3,15 +3,17 @@ package org.kne.cloud.network.klalb;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
|
|
||||||
import org.kne.cloud.network.MultipurposeSocketAddress;
|
import org.kne.cloud.network.MultipurposeSocketAddress;
|
||||||
|
|
||||||
public interface KLALBPacketLink {
|
public interface KLALBPacketLink {
|
||||||
public void setOutputTrafficCounters(AtomicLong[] al);
|
public void setOutputTrafficCounters(LongAdder[] al);
|
||||||
public void setOutputPacketsCounters(AtomicLong[] al);
|
public void setOutputPacketsCounters(LongAdder[] longAdders);
|
||||||
public void setInputTrafficCounters(AtomicLong[] al);
|
public void setInputTrafficCounters(LongAdder[] longAdders);
|
||||||
public void setInputPacketsCounters(AtomicLong[] al);
|
public void setInputPacketsCounters(LongAdder[] al);
|
||||||
public void writePacket(ByteBuffer kp) throws IOException;
|
public void writePacket(ByteBuffer kp) throws IOException;
|
||||||
public default void writePackets(ByteBuffer[] kpp,int off,int len) throws IOException {
|
public default void writePackets(ByteBuffer[] kpp,int off,int len) throws IOException {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
@@ -29,5 +31,6 @@ public interface KLALBPacketLink {
|
|||||||
@Override
|
@Override
|
||||||
public String toString();
|
public String toString();
|
||||||
public boolean isStream();
|
public boolean isStream();
|
||||||
|
public void writeKLALBPackets(List<KLALBPacket> kp) throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.io.Reader;
|
|||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
@@ -47,7 +48,7 @@ public class KLALBProxySystem {
|
|||||||
private Gson gson;
|
private Gson gson;
|
||||||
private File jsonFile;
|
private File jsonFile;
|
||||||
{
|
{
|
||||||
GsonBuilder gb=new GsonBuilder();
|
GsonBuilder gb=new GsonBuilder().setPrettyPrinting();
|
||||||
MultipurposeSocketAddress.registerToGsonBuilder(gb);
|
MultipurposeSocketAddress.registerToGsonBuilder(gb);
|
||||||
KLALBConfigItem.registerToGsonBuilder(gb);
|
KLALBConfigItem.registerToGsonBuilder(gb);
|
||||||
gson=gb.create();
|
gson=gb.create();
|
||||||
@@ -169,7 +170,7 @@ public class KLALBProxySystem {
|
|||||||
|
|
||||||
String vsne=kcci.getVirtualSocketName();
|
String vsne=kcci.getVirtualSocketName();
|
||||||
//if(vsne!=null) {
|
//if(vsne!=null) {
|
||||||
MultipurposeSocketAddress.getSocketTypeRegister().put(vsne, klalbController.getSocketType());
|
MultipurposeSocketAddress.getSocketTypeRegister().put(vsne, klalbController.getStreamSocketType());
|
||||||
//}
|
//}
|
||||||
MultipurposeSocketAddress tcple=kcci.getTCPListen();
|
MultipurposeSocketAddress tcple=kcci.getTCPListen();
|
||||||
if(tcple!=null) {
|
if(tcple!=null) {
|
||||||
@@ -180,7 +181,7 @@ public class KLALBProxySystem {
|
|||||||
|
|
||||||
tcpl.setCon((soc)->{
|
tcpl.setCon((soc)->{
|
||||||
|
|
||||||
KLALBRemoteLine krs=null;
|
KLALBRemoteLine krs=null;
|
||||||
try {
|
try {
|
||||||
krs = new KLALBRemoteLine(new StreamChannelKLALBPacketLink(soc));
|
krs = new KLALBRemoteLine(new StreamChannelKLALBPacketLink(soc));
|
||||||
klalbController.addRemoteLine(krs);
|
klalbController.addRemoteLine(krs);
|
||||||
@@ -220,10 +221,7 @@ public class KLALBProxySystem {
|
|||||||
}
|
}
|
||||||
List<MultipurposeSocketAddress> linele=kcci.getLineTable();
|
List<MultipurposeSocketAddress> linele=kcci.getLineTable();
|
||||||
if(linele!=null) {
|
if(linele!=null) {
|
||||||
linele.forEach((aline)->{
|
klalbController.getSelflineTable().addAll(linele);
|
||||||
klalbController.getSelflineTable().add(aline);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
List<MultipurposeSocketAddress> linetoc=kcci.getConnectLineTable();
|
List<MultipurposeSocketAddress> linetoc=kcci.getConnectLineTable();
|
||||||
if(linetoc!=null) {
|
if(linetoc!=null) {
|
||||||
@@ -231,6 +229,24 @@ public class KLALBProxySystem {
|
|||||||
klalbController.addRemoteLines(aline);
|
klalbController.addRemoteLines(aline);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<MultipurposeSocketAddress> ntps=kcci.getNtpServerTable();
|
||||||
|
if(ntps!=null) {
|
||||||
|
klalbController.getNTPTable().addAll(ntps);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> strexc=kcci.getNetworkInterfaceExcepts();
|
||||||
|
klalbController.getNetworkInterfaceExcept().clear();
|
||||||
|
if(strexc!=null) {
|
||||||
|
for(String strexci:strexc) {
|
||||||
|
try {
|
||||||
|
klalbController.getNetworkInterfaceExcept().add(NetworkInterface.getByName(strexci));
|
||||||
|
} catch (SocketException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}else if(item instanceof SocketBridgeConfigItem) {
|
}else if(item instanceof SocketBridgeConfigItem) {
|
||||||
SocketBridgeConfigItem scci=(SocketBridgeConfigItem) item;
|
SocketBridgeConfigItem scci=(SocketBridgeConfigItem) item;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.util.Set;
|
|||||||
import org.kne.cloud.network.MultipurposeSocketAddress;
|
import org.kne.cloud.network.MultipurposeSocketAddress;
|
||||||
import org.kne.cloud.network.Proxy;
|
import org.kne.cloud.network.Proxy;
|
||||||
import org.kne.cloud.network.SocketListener;
|
import org.kne.cloud.network.SocketListener;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
|
||||||
import org.kne.cloud.network.monitor.MonitorData;
|
import org.kne.cloud.network.monitor.MonitorData;
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
@@ -64,10 +65,14 @@ public class KLALBRemoteManagement {
|
|||||||
switch (reqt) {
|
switch (reqt) {
|
||||||
case "GETLINES":
|
case "GETLINES":
|
||||||
JsonArray lines=new JsonArray();
|
JsonArray lines=new JsonArray();
|
||||||
List<KLALBRemoteLine>lineslist= klalbProxySystem.getKlalbController().getLines();
|
List<IPv6NetworkLink>lineslist= klalbProxySystem.getKlalbController().getLines();
|
||||||
synchronized (lineslist) {
|
synchronized (lineslist) {
|
||||||
for (Iterator<KLALBRemoteLine> iterator = lineslist.iterator(); iterator.hasNext();) {
|
for (Iterator<IPv6NetworkLink> iterator = lineslist.iterator(); iterator.hasNext();) {
|
||||||
KLALBRemoteLine klalbRemoteLine = (KLALBRemoteLine) iterator.next();
|
IPv6NetworkLink link=iterator.next();
|
||||||
|
if(!(link instanceof KLALBRemoteLine)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
KLALBRemoteLine klalbRemoteLine = (KLALBRemoteLine) link;
|
||||||
if(klalbRemoteLine.getSocketAddress()==null)
|
if(klalbRemoteLine.getSocketAddress()==null)
|
||||||
continue;
|
continue;
|
||||||
JsonObject jklbrl=new JsonObject();
|
JsonObject jklbrl=new JsonObject();
|
||||||
|
|||||||
@@ -39,8 +39,43 @@ public class KLALBUtils {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println(uuidToIP(new UUID(-1,-1)));
|
System.out.println(uuidToIP(new UUID(-1,-1)));
|
||||||
}
|
}
|
||||||
public static String bytesUnit(long v) {
|
|
||||||
if (v >= 1024L * 1024 * 1024 * 1024 * 1024) {
|
public static String convertUintNanoDefalut(long v) {
|
||||||
|
if(v>=1000L*1000L*1000L*1000L*1000L) {
|
||||||
|
return format( v/(1000.0*1000.0*1000.0*1000.0*1000.0))+"M";
|
||||||
|
}else if(v>=1000L*1000L*1000L*1000L) {
|
||||||
|
return format (v/(1000.0*1000.0*1000.0*1000.0))+"K";
|
||||||
|
}else if(v>=1000L*1000L*1000L) {
|
||||||
|
return format( v/(1000.0*1000.0*1000.0));
|
||||||
|
}else if(v>=1000L*1000L) {
|
||||||
|
return format( v/(1000.0*1000.0))+"m";
|
||||||
|
}else if(v>=1000L) {
|
||||||
|
return format( v/(1000.0))+"u";
|
||||||
|
}else {
|
||||||
|
return Long.toString(v)+"n" ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertUintDefalut(long v) {
|
||||||
|
if(v>=1000L*1000L*1000L*1000L*1000L) {
|
||||||
|
return format( v/(1000.0*1000.0*1000.0*1000.0*1000.0))+"P";
|
||||||
|
}else if(v>=1000L*1000L*1000L*1000L) {
|
||||||
|
return format (v/(1000.0*1000.0*1000.0*1000.0))+"T";
|
||||||
|
}else if(v>=1000L*1000L*1000L) {
|
||||||
|
return format( v/(1000.0*1000.0*1000.0))+"G";
|
||||||
|
}else if(v>=1000L*1000L) {
|
||||||
|
return format( v/(1000.0*1000.0))+"M";
|
||||||
|
}else if(v>=1000L) {
|
||||||
|
return format( v/(1000.0))+"K";
|
||||||
|
}else {
|
||||||
|
return Long.toString(v) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String convertIBUint(long v) {
|
||||||
|
return convertIUintDefalut(v)+"B";
|
||||||
|
/*if (v >= 1024L * 1024 * 1024 * 1024 * 1024) {
|
||||||
return String.format("%.2f", v / (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0)) + "PB";
|
return String.format("%.2f", v / (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0)) + "PB";
|
||||||
} else if (v >= 1024L * 1024 * 1024 * 1024) {
|
} else if (v >= 1024L * 1024 * 1024 * 1024) {
|
||||||
return String.format("%.2f", v / (1024.0 * 1024.0 * 1024.0 * 1024.0)) + "TB";
|
return String.format("%.2f", v / (1024.0 * 1024.0 * 1024.0 * 1024.0)) + "TB";
|
||||||
@@ -52,9 +87,9 @@ public class KLALBUtils {
|
|||||||
return String.format("%.2f", v / (1024.0)) + "KB";
|
return String.format("%.2f", v / (1024.0)) + "KB";
|
||||||
} else {
|
} else {
|
||||||
return v + "B";
|
return v + "B";
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
public static String bytesUnitSimp(long v) {
|
public static String convertIBUintSimp(long v) {
|
||||||
if(v>=1024L*1024*1024*1024*1024) {
|
if(v>=1024L*1024*1024*1024*1024) {
|
||||||
return format( v/(1024.0*1024.0*1024.0*1024.0*1024.0))+"P";
|
return format( v/(1024.0*1024.0*1024.0*1024.0*1024.0))+"P";
|
||||||
}else if(v>=1024L*1024*1024*1024) {
|
}else if(v>=1024L*1024*1024*1024) {
|
||||||
@@ -71,17 +106,17 @@ public class KLALBUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String defaultUnit(long v) {
|
public static String convertIUintDefalut(long v) {
|
||||||
if(v>=1024L*1024*1024*1024*1024) {
|
if(v>=1024L*1024*1024*1024*1024) {
|
||||||
return format( v/(1024.0*1024.0*1024.0*1024.0*1024.0))+"P";
|
return format( v/(1024.0*1024.0*1024.0*1024.0*1024.0))+"Pi";
|
||||||
}else if(v>=1024L*1024*1024*1024) {
|
}else if(v>=1024L*1024*1024*1024) {
|
||||||
return format (v/(1024.0*1024.0*1024.0*1024.0))+"T";
|
return format (v/(1024.0*1024.0*1024.0*1024.0))+"Ti";
|
||||||
}else if(v>=1024L*1024*1024) {
|
}else if(v>=1024L*1024*1024) {
|
||||||
return format( v/(1024.0*1024.0*1024.0))+"G";
|
return format( v/(1024.0*1024.0*1024.0))+"Gi";
|
||||||
}else if(v>=1024L*1024) {
|
}else if(v>=1024L*1024) {
|
||||||
return format( v/(1024.0*1024.0))+"M";
|
return format( v/(1024.0*1024.0))+"Mi";
|
||||||
}else if(v>=1024L) {
|
}else if(v>=1024L) {
|
||||||
return format( v/(1024.0))+"K";
|
return format( v/(1024.0))+"Ki";
|
||||||
}else {
|
}else {
|
||||||
return Long.toString(v) ;
|
return Long.toString(v) ;
|
||||||
}
|
}
|
||||||
@@ -164,9 +199,9 @@ public class KLALBUtils {
|
|||||||
if (targetAddress.supportNIO()) {
|
if (targetAddress.supportNIO()) {
|
||||||
if (bindAddress != null) {
|
if (bindAddress != null) {
|
||||||
return new StreamChannelKLALBPacketLink(targetAddress
|
return new StreamChannelKLALBPacketLink(targetAddress
|
||||||
.connectSocketChannel(InetAddress.getByName(bindAddress.getHost()), bindAddress.getPort()));
|
.connectSocketChannel(InetAddress.getByName(bindAddress.getHost()), bindAddress.getPort()),buffered);
|
||||||
} else {
|
} else {
|
||||||
return new StreamChannelKLALBPacketLink(targetAddress.connectSocketChannel());
|
return new StreamChannelKLALBPacketLink(targetAddress.connectSocketChannel(),buffered);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bindAddress != null) {
|
if (bindAddress != null) {
|
||||||
@@ -192,10 +227,10 @@ public class KLALBUtils {
|
|||||||
if (bindAddress != null) {
|
if (bindAddress != null) {
|
||||||
if(buffered) {
|
if(buffered) {
|
||||||
return new StreamChannelKLALBPacketLink(targetAddress
|
return new StreamChannelKLALBPacketLink(targetAddress
|
||||||
.connectSocketChannel(InetAddress.getByName(bindAddress.getHost()), bindAddress.getPort(),timeout));
|
.connectSocketChannel(InetAddress.getByName(bindAddress.getHost()), bindAddress.getPort(),timeout),buffered);
|
||||||
}else {
|
}else {
|
||||||
return new StreamChannelKLALBPacketLink(targetAddress
|
return new StreamChannelKLALBPacketLink(targetAddress
|
||||||
.connectSocketChannel(InetAddress.getByName(bindAddress.getHost()), bindAddress.getPort(),timeout));
|
.connectSocketChannel(InetAddress.getByName(bindAddress.getHost()), bindAddress.getPort(),timeout),buffered);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(buffered) {
|
if(buffered) {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package org.kne.cloud.network.klalb;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.DatagramServerSocket;
|
||||||
|
import org.kne.cloud.network.DatagramServerSocketFactory;
|
||||||
|
|
||||||
|
public class KLALBVirtualDatagramServerSocketFactory extends DatagramServerSocketFactory {
|
||||||
|
private KLALBController controller;
|
||||||
|
|
||||||
|
public KLALBVirtualDatagramServerSocketFactory(KLALBController controller) {
|
||||||
|
this.controller=controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KLALBController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public DatagramServerSocket createDatagramServerSocket(int port) throws IOException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatagramServerSocket createDatagramServerSocket(int port, int backlog) throws IOException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatagramServerSocket createDatagramServerSocket(int port, int backlog, InetAddress ifAddress)
|
||||||
|
throws IOException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.kne.cloud.network.klalb;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.VirtualDatagramSocket;
|
||||||
|
import org.kne.cloud.network.VirtualDatagramSocketImpl;
|
||||||
|
import org.pcap4j.core.Inets;
|
||||||
|
|
||||||
|
public class KLALBVirtualDatagramSocket extends VirtualDatagramSocket {
|
||||||
|
|
||||||
|
private KLALBController controller;
|
||||||
|
|
||||||
|
// 默认构造函数
|
||||||
|
public KLALBVirtualDatagramSocket(KLALBController controller) throws SocketException {
|
||||||
|
this(controller,new InetSocketAddress(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定到指定Socket地址
|
||||||
|
public KLALBVirtualDatagramSocket(KLALBController controller, SocketAddress bindaddr) throws SocketException {
|
||||||
|
super(controller.createVirtualDatagramSocketImpl());
|
||||||
|
this.controller = controller;
|
||||||
|
if (bindaddr != null) {
|
||||||
|
bind(bindaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定到指定端口
|
||||||
|
public KLALBVirtualDatagramSocket(KLALBController controller, int port) throws SocketException {
|
||||||
|
this(controller, port, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定到指定端口和本地地址
|
||||||
|
public KLALBVirtualDatagramSocket(KLALBController controller, int port, InetAddress laddr) throws SocketException {
|
||||||
|
this(controller);
|
||||||
|
if (laddr == null) {
|
||||||
|
bind(new InetSocketAddress(port));
|
||||||
|
} else {
|
||||||
|
bind(new InetSocketAddress(laddr, port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package org.kne.cloud.network.klalb;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.DatagramSocketFactory;
|
||||||
|
|
||||||
|
public class KLALBVirtualDatagramSocketFactory extends DatagramSocketFactory {
|
||||||
|
private KLALBController controller;
|
||||||
|
|
||||||
|
public KLALBVirtualDatagramSocketFactory(KLALBController controller) {
|
||||||
|
this.controller=controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KLALBController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatagramSocket createSocket() throws IOException {
|
||||||
|
return new KLALBVirtualDatagramSocket(controller,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatagramSocket createSocket(String paramString, int paramInt) throws IOException, UnknownHostException {
|
||||||
|
DatagramSocket dg=new KLALBVirtualDatagramSocket(controller);
|
||||||
|
dg.connect(new InetSocketAddress(paramString, paramInt));
|
||||||
|
return dg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatagramSocket createSocket(InetAddress paramInetAddress, int paramInt) throws IOException {
|
||||||
|
DatagramSocket dg=new KLALBVirtualDatagramSocket(controller);
|
||||||
|
dg.connect(paramInetAddress, paramInt);
|
||||||
|
return dg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatagramSocket createSocket(String paramString, int paramInt1, InetAddress paramInetAddress, int paramInt2)
|
||||||
|
throws IOException, UnknownHostException {
|
||||||
|
DatagramSocket dg=new KLALBVirtualDatagramSocket(controller,new InetSocketAddress(paramInetAddress, paramInt2));
|
||||||
|
dg.connect(new InetSocketAddress(paramString, paramInt1));
|
||||||
|
return dg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatagramSocket createSocket(InetAddress paramInetAddress1, int paramInt1, InetAddress paramInetAddress2,
|
||||||
|
int paramInt2) throws IOException {
|
||||||
|
DatagramSocket dg=new KLALBVirtualDatagramSocket(controller,new InetSocketAddress(paramInetAddress2, paramInt2));
|
||||||
|
dg.connect(paramInetAddress1, paramInt1);
|
||||||
|
return dg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
package org.kne.cloud.network.klalb;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.BindException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocketImpl;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.BufferOverflowException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
import org.kne.cloud.network.VirtualDatagramSocketImpl;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
|
import org.kne.cloud.network.tcp.UDPPacket;
|
||||||
|
import org.kne.concurrent.HighPerformanceExecutor;
|
||||||
|
import org.kne.io.KNEChannels;
|
||||||
|
|
||||||
|
public class KLALBVirtualDatagramSocketImpl extends VirtualDatagramSocketImpl implements BindableKLALBPacketConsumer{
|
||||||
|
|
||||||
|
private KLALBController controller;
|
||||||
|
|
||||||
|
private volatile boolean closed=false;
|
||||||
|
|
||||||
|
protected Inet6Address remoteaddr;
|
||||||
|
protected Inet6Address localaddr;
|
||||||
|
|
||||||
|
protected int remotePort;{
|
||||||
|
try {
|
||||||
|
localaddr=(Inet6Address) Inet6Address.getByName("::0");
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private boolean ignoreBindCheck=false;
|
||||||
|
|
||||||
|
private int ttl=255;
|
||||||
|
|
||||||
|
|
||||||
|
private volatile int inputchachesize = 1024*1024;
|
||||||
|
|
||||||
|
public KLALBVirtualDatagramSocketImpl(KLALBController controller) {
|
||||||
|
this.controller=controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOption(int optID, Object value) throws SocketException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getOption(int optID) throws SocketException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void create() throws SocketException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void bind(int port, InetAddress host) throws SocketException {
|
||||||
|
try {
|
||||||
|
if (host.equals(Inet4Address.getByName("0.0.0.0"))) {
|
||||||
|
host = Inet6Address.getByName("::0");
|
||||||
|
}
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (!(host instanceof Inet6Address)) {
|
||||||
|
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 virtualaddress");
|
||||||
|
}
|
||||||
|
if ((!host.isAnyLocalAddress()) && (!host.equals(controller.getSelf().getAddress()))) {
|
||||||
|
throw new BindException("must bind to self");
|
||||||
|
}
|
||||||
|
localaddr = (Inet6Address) host;
|
||||||
|
localPort=port;
|
||||||
|
if(!ignoreBindCheck)
|
||||||
|
controller.getDatagramPortBinder().bind(this);
|
||||||
|
controller.getDatagramPortBinder().listen(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void send(DatagramPacket p) throws IOException {
|
||||||
|
UDPPacket udp=new UDPPacket(localPort, p.getPort());
|
||||||
|
udp.getData().put(p.getData(), p.getOffset(), p.getLength());
|
||||||
|
udp.getData().flip();
|
||||||
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
|
controller.sendPacketToAddress((Inet6Address) p.getAddress(),0, udp);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int peek(InetAddress i) throws IOException {
|
||||||
|
return peekNextPacket().getSrcPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int peekData(DatagramPacket p) throws IOException {
|
||||||
|
UDPPacket pack=peekNextPacket();
|
||||||
|
copyTo(pack, p);
|
||||||
|
return p.getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void receive(DatagramPacket p) throws IOException {
|
||||||
|
UDPPacket pack=pollNextPacket();
|
||||||
|
copyTo(pack, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyTo(UDPPacket pack, DatagramPacket p) throws IOException {
|
||||||
|
p.setAddress(pack.getParent().getSourceAddress());
|
||||||
|
p.setPort(pack.getSrcPort());
|
||||||
|
ByteBuffer buffer= ByteBuffer.wrap(p.getData(),p.getOffset(),p.getLength());
|
||||||
|
|
||||||
|
try {
|
||||||
|
buffer.put(pack.getData());
|
||||||
|
pack.getData().rewind();
|
||||||
|
}catch(BufferOverflowException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
buffer.flip();
|
||||||
|
p.setLength(buffer.limit());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setTTL(byte ttl) throws IOException {
|
||||||
|
this.ttl=ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte getTTL() throws IOException {
|
||||||
|
return (byte) ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setTimeToLive(int ttl) throws IOException {
|
||||||
|
this.ttl=ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getTimeToLive() throws IOException {
|
||||||
|
return ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void join(InetAddress inetaddr) throws IOException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void leave(InetAddress inetaddr) throws IOException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
|
||||||
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void close() {
|
||||||
|
controller.getDatagramPortBinder().unlisten(this);
|
||||||
|
if(!ignoreBindCheck)
|
||||||
|
controller.getDatagramPortBinder().unbind(this);
|
||||||
|
closed=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private volatile Thread parkThread;
|
||||||
|
private UDPPacket peekNextPacket() {
|
||||||
|
UDPPacket pol=null;
|
||||||
|
while(true) {
|
||||||
|
pol=recvQueue.peek();
|
||||||
|
if(pol!=null) {
|
||||||
|
recvQueueUsed.addAndGet((int) -pol.getDataLength());
|
||||||
|
return pol;
|
||||||
|
}
|
||||||
|
parkThread=Thread.currentThread();
|
||||||
|
LockSupport.parkNanos(1000000L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private UDPPacket pollNextPacket() {
|
||||||
|
UDPPacket pol=null;
|
||||||
|
while(true) {
|
||||||
|
pol=recvQueue.poll();
|
||||||
|
if(pol!=null) {
|
||||||
|
recvQueueUsed.addAndGet((int) -pol.getDataLength());
|
||||||
|
return pol;
|
||||||
|
}
|
||||||
|
parkThread=Thread.currentThread();
|
||||||
|
LockSupport.parkNanos(1000000L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Queue<UDPPacket> recvQueue = new ConcurrentLinkedQueue<UDPPacket>();
|
||||||
|
private AtomicInteger recvQueueUsed=new AtomicInteger(0);
|
||||||
|
@Override
|
||||||
|
public void accept(Inet6Address t,NetworkPacket np) {
|
||||||
|
UDPPacket u=(UDPPacket) np;
|
||||||
|
if(recvQueueUsed.get()<=inputchachesize) {
|
||||||
|
if(recvQueue.offer(u)) {
|
||||||
|
recvQueueUsed.addAndGet((int) u.getDataLength());
|
||||||
|
LockSupport.unpark(parkThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetAddress getRemoteInetAddress() {
|
||||||
|
return remoteaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetAddress getLocalInetAddress() {
|
||||||
|
return localaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPort() {
|
||||||
|
return remotePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLocalPort(int i) {
|
||||||
|
this.localPort=i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLocalPort() {
|
||||||
|
return super.getLocalPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,18 +7,19 @@ import java.net.SocketException;
|
|||||||
import org.kne.cloud.network.RawSocket;
|
import org.kne.cloud.network.RawSocket;
|
||||||
import org.kne.cloud.network.RawSocketImpl;
|
import org.kne.cloud.network.RawSocketImpl;
|
||||||
import org.kne.cloud.network.VirtualRawSocket;
|
import org.kne.cloud.network.VirtualRawSocket;
|
||||||
|
import org.kne.cloud.network.ipv6.LoopbackIPv6NetworkLink;
|
||||||
import org.kne.cloud.network.srv6.SRv6Router;
|
import org.kne.cloud.network.srv6.SRv6Router;
|
||||||
|
|
||||||
public class KLALBVirtualRawSocket extends VirtualRawSocket {
|
public class KLALBVirtualRawSocket extends VirtualRawSocket {
|
||||||
|
|
||||||
public KLALBVirtualRawSocket(SRv6Router controller) {
|
public KLALBVirtualRawSocket(LoopbackIPv6NetworkLink controller) {
|
||||||
super(new KLALBVirtualRawSocketImpl(controller));
|
super(new KLALBVirtualRawSocketImpl(controller));
|
||||||
}
|
}
|
||||||
|
|
||||||
public KLALBVirtualRawSocket(SRv6Router controller,Inet6Address bindAddress) throws SocketException {
|
public KLALBVirtualRawSocket(LoopbackIPv6NetworkLink controller,Inet6Address bindAddress) throws SocketException {
|
||||||
super(new KLALBVirtualRawSocketImpl(controller),bindAddress);
|
super(new KLALBVirtualRawSocketImpl(controller),bindAddress);
|
||||||
}
|
}
|
||||||
public KLALBVirtualRawSocket(SRv6Router controller,Inet6Address bindAddress,int bindProtocol) throws SocketException {
|
public KLALBVirtualRawSocket(LoopbackIPv6NetworkLink controller,Inet6Address bindAddress,int bindProtocol) throws SocketException {
|
||||||
super(new KLALBVirtualRawSocketImpl(controller),bindAddress,bindProtocol);
|
super(new KLALBVirtualRawSocketImpl(controller),bindAddress,bindProtocol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.util.Queue;
|
|||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.locks.LockSupport;
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.kne.cloud.network.ByteBufferAllocator;
|
import org.kne.cloud.network.ByteBufferAllocator;
|
||||||
import org.kne.cloud.network.NetworkPacket;
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
@@ -23,6 +24,8 @@ import org.kne.cloud.network.ThreadTool;
|
|||||||
import org.kne.cloud.network.VirtualRawSocketImpl;
|
import org.kne.cloud.network.VirtualRawSocketImpl;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6Payload;
|
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6Payload;
|
||||||
|
import org.kne.cloud.network.ipv6.Inet6AddressGroup;
|
||||||
|
import org.kne.cloud.network.ipv6.LoopbackIPv6NetworkLink;
|
||||||
import org.kne.cloud.network.srv6.PacketConsumer;
|
import org.kne.cloud.network.srv6.PacketConsumer;
|
||||||
import org.kne.cloud.network.srv6.SRv6Router;
|
import org.kne.cloud.network.srv6.SRv6Router;
|
||||||
import org.kne.concurrent.HighPerformanceExecutor;
|
import org.kne.concurrent.HighPerformanceExecutor;
|
||||||
@@ -32,7 +35,7 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
|
|
||||||
private boolean ipHeaderInclude=false;
|
private boolean ipHeaderInclude=false;
|
||||||
|
|
||||||
private SRv6Router router;
|
private LoopbackIPv6NetworkLink link;
|
||||||
|
|
||||||
|
|
||||||
protected volatile Inet6Address remoteaddr;
|
protected volatile Inet6Address remoteaddr;
|
||||||
@@ -42,13 +45,13 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
|
|
||||||
private volatile int inputchachesize = 1024*1024;
|
private volatile int inputchachesize = 1024*1024;
|
||||||
|
|
||||||
protected SRv6Router getRouter() {
|
protected LoopbackIPv6NetworkLink getLoopbackLink() {
|
||||||
return router;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KLALBVirtualRawSocketImpl(SRv6Router router) {
|
public KLALBVirtualRawSocketImpl(LoopbackIPv6NetworkLink link) {
|
||||||
super();
|
super();
|
||||||
this.router = router;
|
this.link = link;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -116,7 +119,7 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void close() {
|
protected void close() {
|
||||||
router.getProtocolNumberRegister().remove(bindProtocolNumber);
|
link.getProtocolNumberRegister().remove(bindProtocolNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -134,13 +137,22 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
if (!(address instanceof Inet6Address)) {
|
if (!(address instanceof Inet6Address)) {
|
||||||
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 address");
|
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 address");
|
||||||
}
|
}
|
||||||
if ((!address.isAnyLocalAddress()) && (!address.equals(router.getLocator().getAddress()))) {
|
if (!address.isAnyLocalAddress() ) {
|
||||||
|
boolean contains=false;
|
||||||
|
for(Inet6AddressGroup adg:link.getAddressGroups()) {
|
||||||
|
if(adg.checkMatch((Inet6Address) address)) {
|
||||||
|
contains=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!contains) {
|
||||||
throw new BindException("must bind to self");
|
throw new BindException("must bind to self");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
localaddr=(Inet6Address) address;
|
localaddr=(Inet6Address) address;
|
||||||
this.bindProtocolNumber=protocolNumber;
|
this.bindProtocolNumber=protocolNumber;
|
||||||
if(router.getProtocolNumberRegister().putIfAbsent(protocolNumber, this)!=null) {
|
if(link.getProtocolNumberRegister().putIfAbsent(protocolNumber, this)!=null) {
|
||||||
throw new BindException("protocol number already bind");
|
throw new BindException("protocol number already bind");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +193,11 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
ipv.setTrafficClass(0);
|
ipv.setTrafficClass(0);
|
||||||
ipv.setFlowLabel(0);
|
ipv.setFlowLabel(0);
|
||||||
ipv.setHopLimit(255);
|
ipv.setHopLimit(255);
|
||||||
ipv.setSourceAddress(router.getLocator().getAddress());
|
if(!localaddr.isAnyLocalAddress()) {
|
||||||
|
ipv.setSourceAddress(localaddr);
|
||||||
|
}else {
|
||||||
|
ipv.setSourceAddress(link.getRouter().getLocator().getAddress());
|
||||||
|
}
|
||||||
InetAddress address= p.getAddress();
|
InetAddress address= p.getAddress();
|
||||||
if (!(address instanceof Inet6Address)) {
|
if (!(address instanceof Inet6Address)) {
|
||||||
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 address");
|
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 address");
|
||||||
@@ -193,7 +209,10 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
pl.getData().put(buf);
|
pl.getData().put(buf);
|
||||||
pl.getData().flip();
|
pl.getData().flip();
|
||||||
ipv.setPayload(pl);
|
ipv.setPayload(pl);
|
||||||
router.insertSRHandRoutePacket(ipv);
|
Consumer<IPv6Packet>cons=link.getReceiveConsumer();
|
||||||
|
if(cons!=null) {
|
||||||
|
cons.accept(ipv);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,7 +232,7 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
p.setAddress(pack.getSourceAddress());
|
p.setAddress(pack.getSourceAddress());
|
||||||
ByteBuffer buffer= ByteBuffer.wrap(p.getData(),p.getOffset(),p.getLength());
|
ByteBuffer buffer= ByteBuffer.wrap(p.getData(),p.getOffset(),p.getLength());
|
||||||
if(ipHeaderInclude) {
|
if(ipHeaderInclude) {
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
try {
|
try {
|
||||||
pack.getPayload().writeToChannel(KNEChannels.newWritableChannel(buffer));
|
pack.getPayload().writeToChannel(KNEChannels.newWritableChannel(buffer));
|
||||||
@@ -236,7 +255,7 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
while(true) {
|
while(true) {
|
||||||
pol=recvQueue.peek();
|
pol=recvQueue.peek();
|
||||||
if(pol!=null) {
|
if(pol!=null) {
|
||||||
recvQueueUsed.addAndGet((int) -pol.getPayload().getLength());
|
recvQueueUsed.addAndGet((int) -pol.getPayload().getTotalLength());
|
||||||
return pol;
|
return pol;
|
||||||
}
|
}
|
||||||
parkThread=Thread.currentThread();
|
parkThread=Thread.currentThread();
|
||||||
@@ -248,7 +267,7 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
while(true) {
|
while(true) {
|
||||||
pol=recvQueue.poll();
|
pol=recvQueue.poll();
|
||||||
if(pol!=null) {
|
if(pol!=null) {
|
||||||
recvQueueUsed.addAndGet((int) -pol.getPayload().getLength());
|
recvQueueUsed.addAndGet((int) -pol.getPayload().getTotalLength());
|
||||||
return pol;
|
return pol;
|
||||||
}
|
}
|
||||||
parkThread=Thread.currentThread();
|
parkThread=Thread.currentThread();
|
||||||
@@ -259,14 +278,14 @@ public class KLALBVirtualRawSocketImpl extends VirtualRawSocketImpl implements P
|
|||||||
private AtomicInteger recvQueueUsed=new AtomicInteger(0);
|
private AtomicInteger recvQueueUsed=new AtomicInteger(0);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(IPv6Packet packx) throws IOException {
|
public boolean accept(IPv6Packet packx) throws IOException {
|
||||||
if(recvQueueUsed.get()<=inputchachesize) {
|
if(recvQueueUsed.get()<=inputchachesize) {
|
||||||
if(recvQueue.offer(packx)) {
|
if(recvQueue.offer(packx)) {
|
||||||
recvQueueUsed.addAndGet((int) packx.getPayload().getLength());
|
recvQueueUsed.addAndGet((int) packx.getPayload().getTotalLength());
|
||||||
LockSupport.unpark(parkThread);
|
LockSupport.unpark(parkThread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class KLALBVirtualServerSocket extends VirtualServerSocket {
|
|||||||
private KLALBController controler;
|
private KLALBController controler;
|
||||||
protected ServerSocketChannel channel;
|
protected ServerSocketChannel channel;
|
||||||
public KLALBVirtualServerSocket(KLALBController controler) throws IOException {
|
public KLALBVirtualServerSocket(KLALBController controler) throws IOException {
|
||||||
super(controler.createVirtualImpl());
|
super(controler.createVirtualSocketImpl());
|
||||||
this.controler=controler;
|
this.controler=controler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class KLALBVirtualSocket extends VirtualSocket {
|
|||||||
protected SocketChannel channel;
|
protected SocketChannel channel;
|
||||||
|
|
||||||
public KLALBVirtualSocket(KLALBController controler) throws SocketException {
|
public KLALBVirtualSocket(KLALBController controler) throws SocketException {
|
||||||
super(controler.createVirtualImpl());
|
super(controler.createVirtualSocketImpl());
|
||||||
this.controller = controler;
|
this.controller = controler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,4 +155,8 @@ public class KLALBVirtualSocketChannel extends SocketChannel{
|
|||||||
public void setAutoFlush(boolean b) throws IOException {
|
public void setAutoFlush(boolean b) throws IOException {
|
||||||
((KVSIOutputStream)socket.getOutputStream()).setAutoFlush(b);
|
((KVSIOutputStream)socket.getOutputStream()).setAutoFlush(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() throws IOException {
|
||||||
|
((KVSIOutputStream)socket.getOutputStream()).flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,11 +56,16 @@ import java.util.zip.GZIPInputStream;
|
|||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
import java.util.zip.InflaterInputStream;
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
import org.kne.cloud.network.PortPair;
|
import org.kne.cloud.network.PortPair;
|
||||||
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.VirtualSocketImpl;
|
import org.kne.cloud.network.VirtualSocketImpl;
|
||||||
|
import org.kne.cloud.network.congress.CongressAlgorithm;
|
||||||
|
import org.kne.cloud.network.congress.ECNCongressAlgorithm;
|
||||||
|
import org.kne.cloud.network.congress.LARCCongressAlgorithm;
|
||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||||
|
import org.kne.concurrent.HighPerformanceExecutor;
|
||||||
import org.kne.concurrent.SpinLock;
|
import org.kne.concurrent.SpinLock;
|
||||||
import org.kne.concurrent.ThreadParker;
|
import org.kne.concurrent.ThreadParker;
|
||||||
import org.kne.debug.TimeDebugger;
|
import org.kne.debug.TimeDebugger;
|
||||||
@@ -69,10 +74,10 @@ import org.kne.io.Data;
|
|||||||
import com.google.gson.internal.Pair;
|
import com.google.gson.internal.Pair;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements BindableKLALBPacketConsumer{
|
public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements BindableKLALBPacketConsumer{
|
||||||
|
|
||||||
private static final int HEADER_CALIBRATE = 40;
|
private static final int HEADER_CALIBRATE = 80;
|
||||||
/*
|
/*
|
||||||
private PrintStream dbg;
|
private PrintStream dbg;
|
||||||
{
|
{
|
||||||
@@ -84,6 +89,9 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
|
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
private static final boolean debug = false;
|
||||||
|
|
||||||
|
|
||||||
private SpeedAndTrafficAndDelayMonitorDataImpl socketMonitor=new SpeedAndTrafficAndDelayMonitorDataImpl();
|
private SpeedAndTrafficAndDelayMonitorDataImpl socketMonitor=new SpeedAndTrafficAndDelayMonitorDataImpl();
|
||||||
@@ -94,13 +102,13 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
|
|
||||||
|
|
||||||
//60000 30 30
|
//60000 30 30
|
||||||
private final int MTU=60000;
|
private final int MTU=8192;
|
||||||
private final long MIN_RTTVAR=100000000L;
|
private final long MIN_RTTVAR=200000000L;
|
||||||
private final long MIN_LIMIT_SPEED=64*1024L;
|
private final long MIN_LIMIT_SPEED=128*1024L;
|
||||||
private final long REACK_INTERVAL = 100000000L;
|
private final long REACK_INTERVAL = 100000000L;
|
||||||
|
|
||||||
|
|
||||||
private SpeedLimiter spdlmt=new SpeedLimiter(MIN_LIMIT_SPEED,2000000L);
|
private SpeedLimiter spdlmt=new SpeedLimiter(MIN_LIMIT_SPEED,1000000L);
|
||||||
|
|
||||||
protected Inet6Address remoteaddr;
|
protected Inet6Address remoteaddr;
|
||||||
protected Inet6Address localaddr;{
|
protected Inet6Address localaddr;{
|
||||||
@@ -156,24 +164,15 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
private int inputchachesize =128* 1024*1024;
|
private int inputchachesize =128* 1024*1024;
|
||||||
private int outputchachesize = 128* 1024*1024;
|
private int outputchachesize = 128* 1024*1024;
|
||||||
|
|
||||||
//long pad0,pad1,pad2,pad3,pad4,pad5,pad6,pad7;
|
|
||||||
//4000 100 100
|
|
||||||
//10000 500 500//500
|
|
||||||
private volatile long congressWindowSize = MTU * 40;
|
|
||||||
private volatile long sendWindowSize = MTU * 40;
|
|
||||||
|
|
||||||
private volatile long rcvSpeed=MIN_LIMIT_SPEED;
|
private volatile long congressWindowSize = MTU * 10;
|
||||||
private volatile long requestSpeed=MIN_LIMIT_SPEED;
|
private volatile long sendWindowSize = MTU * 100;
|
||||||
|
|
||||||
private volatile long requestSpeedOld=MIN_LIMIT_SPEED;
|
private volatile long requestSpeedOld=MIN_LIMIT_SPEED;
|
||||||
//private volatile long congressSpeed=0;
|
|
||||||
private volatile double congressFactor=2;
|
|
||||||
|
|
||||||
//private double[] congressFactors=new double[] {0.95,0.95,0.95,1.2,0.8};
|
|
||||||
//private int congressFactorsState=0;
|
|
||||||
//private volatile double maxutilization=0.8;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -182,18 +181,12 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
private long outputcount = 0;
|
private long outputcount = 0;
|
||||||
|
|
||||||
|
|
||||||
private volatile long RTTMin=1000000000L;
|
|
||||||
private volatile long RTTVar=1000000000L;
|
|
||||||
private volatile long RTTAvg=1000000000L;
|
|
||||||
private volatile long RTO=1000000000L;
|
|
||||||
|
|
||||||
private volatile long QueueingAvg=1000000000L;
|
|
||||||
|
|
||||||
//private volatile long RunningSpeed=spdlmt.getLimitspeed();
|
//private volatile long RunningSpeed=spdlmt.getLimitspeed();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private CongressAlgorithm algorithm=new ECNCongressAlgorithm();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -238,21 +231,21 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
try {
|
try {
|
||||||
long x=System.nanoTime();
|
long x=System.nanoTime();
|
||||||
long dt=x-dtp.resendtimer;
|
long dt=x-dtp.resendtimer;
|
||||||
long limit= (long) (Math.pow(2, dtp.getSendCounter()-1)*(RTO*2));
|
long limit= (long) ((1<< (dtp.getSendCounter()-1))*(algorithm.getRTO()*2));
|
||||||
if(dt>limit) {
|
if(dt>limit) {
|
||||||
if(dtp.getSendCounter()>=10) {
|
if(dtp.getSendCounter()>=10) {
|
||||||
throw new IOException("send error!");
|
throw new IOException("send error!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
dtp.setPriority(4);
|
dtp.setPriority(4);
|
||||||
long length= dtp.getLength();
|
long length= dtp.getTotalLength();
|
||||||
socketRawMonitor.getOutTrafficAL().addAndGet(length);
|
socketRawMonitor.getOutTrafficAL().add(length);
|
||||||
spdlmt.forceTransmit(length);
|
spdlmt.forceTransmit(length);
|
||||||
controller.sendPacketToAddress((Inet6Address) remoteaddr,0,dtp,1);
|
controller.sendPacketToAddress((Inet6Address) remoteaddr,0,dtp,1);
|
||||||
//System.out.println("第"+(dtp.getSendCounter()-1)+"次重传:"+dtp+" "+dt+">"+limit);
|
//System.out.println("第"+(dtp.getSendCounter()-1)+"次重传:"+dtp+" "+dt+">"+limit);
|
||||||
dtp.resendtimer=x;
|
dtp.resendtimer=x;
|
||||||
|
});
|
||||||
|
|
||||||
/*if(congressWindowSize>65535) {
|
/*if(congressWindowSize>65535) {
|
||||||
congressWindowSize-=(dtp.getSize()+HEADER_CALIBRATE);
|
congressWindowSize-=(dtp.getSize()+HEADER_CALIBRATE);
|
||||||
@@ -283,19 +276,12 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
|
||||||
if(getLocalPort()!=0&&getPort()!=0)
|
if(getLocalPort()!=0&&getPort()!=0)
|
||||||
if(remoteaddr instanceof Inet6Address&&(!remoteaddr.isAnyLocalAddress()))
|
if(remoteaddr instanceof Inet6Address&&(!remoteaddr.isAnyLocalAddress()))
|
||||||
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
controller.sendPacketToAddress((Inet6Address) remoteaddr,0, new ACKTPacket(getLocalPort(),getPort(), -1,
|
controller.sendPacketToAddress((Inet6Address) remoteaddr,0, new ACKTPacket(getLocalPort(),getPort(), -1,
|
||||||
getAvaliableRcvWindow(),false,socketMonitor.getInSpeedMax(),0));
|
getAvaliableRcvWindow(),false,socketMonitor.getInSpeedMax(),0));
|
||||||
} catch (IOException e) {
|
});
|
||||||
try {
|
|
||||||
close0(true);
|
|
||||||
} catch (IOException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,8 +423,25 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
//System.out.println(c);
|
//System.out.println(c);
|
||||||
spdlmt.setLimitspeed(Math.max(MIN_LIMIT_SPEED,c));
|
spdlmt.setLimitspeed(Math.max(MIN_LIMIT_SPEED,c));
|
||||||
});
|
});
|
||||||
updateBandwidthReq(requestSpeed);
|
//updateBandwidthReq(MIN_LIMIT_SPEED);
|
||||||
|
algorithm.setSpeedControlConsumer((speed,burst)->{
|
||||||
|
if(debug)
|
||||||
|
System.out.println("speed:"+speed);
|
||||||
|
if(portp!=null) {
|
||||||
|
if(speed>requestSpeedOld*1.01||speed<requestSpeedOld*0.99) {
|
||||||
|
updateBandwidthReq(speed);
|
||||||
|
requestSpeedOld=speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spdlmt.setBrustTime(burst);
|
||||||
|
});
|
||||||
|
algorithm.setWindowControlConsumer((window)->{
|
||||||
|
if(debug)
|
||||||
|
System.out.println("window:"+window);
|
||||||
|
congressWindowSize=window;
|
||||||
|
updateWindowSize();
|
||||||
|
});
|
||||||
|
algorithm.reset();
|
||||||
this.portp=portpx;
|
this.portp=portpx;
|
||||||
|
|
||||||
}catch(SocketTimeoutException e) {
|
}catch(SocketTimeoutException e) {
|
||||||
@@ -450,7 +453,6 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
}finally {
|
}finally {
|
||||||
connectionPending=false;
|
connectionPending=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.getResendTimer().schedule(flowControlTask, 5000, 5000);
|
controller.getResendTimer().schedule(flowControlTask, 5000, 5000);
|
||||||
}
|
}
|
||||||
private void updateBandwidthReq(long requestSpeed) {
|
private void updateBandwidthReq(long requestSpeed) {
|
||||||
@@ -477,7 +479,7 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
if (!(host instanceof Inet6Address)) {
|
if (!(host instanceof Inet6Address)) {
|
||||||
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 virtualaddress");
|
throw new IllegalArgumentException("invalid address type, KLALB socket can only use IPV6 virtualaddress");
|
||||||
}
|
}
|
||||||
if ((!host.isAnyLocalAddress()) && (!host.equals(controller.getSelf()))) {
|
if ((!host.isAnyLocalAddress()) && (!host.equals(controller.getSelf().getAddress()))) {
|
||||||
throw new BindException("must bind to self");
|
throw new BindException("must bind to self");
|
||||||
}
|
}
|
||||||
localaddr = (Inet6Address) host;
|
localaddr = (Inet6Address) host;
|
||||||
@@ -577,10 +579,10 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
}
|
}
|
||||||
//System.out.println("PULL:"+dtp2);
|
//System.out.println("PULL:"+dtp2);
|
||||||
dataPack = dtp2;
|
dataPack = dtp2;
|
||||||
socketMonitor.getInTrafficAL().addAndGet(dtp2.getSize());
|
socketMonitor.getInTrafficAL().add(dtp2.getSize());
|
||||||
socketMonitor.getInPacketCounterAL().incrementAndGet();
|
socketMonitor.getInPacketCounterAL().add(1);
|
||||||
controller.getDatatMonitor().getInTrafficAL().addAndGet(dtp2.getSize());
|
controller.getDatatMonitor().getInTrafficAL().add(dtp2.getSize());
|
||||||
controller.getDatatMonitor().getInPacketCounterAL().incrementAndGet();
|
controller.getDatatMonitor().getInPacketCounterAL().add(1);
|
||||||
//checkFlowControl(dtp2);
|
//checkFlowControl(dtp2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -987,58 +989,50 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
tt.cancel();
|
tt.cancel();
|
||||||
tt=null;
|
tt=null;
|
||||||
}
|
}
|
||||||
//TimeDebugger td=new TimeDebugger();
|
|
||||||
//td.putTime("start");
|
|
||||||
dataPack.putTimePassport("packed");
|
dataPack.putTimePassport("packed");
|
||||||
/*while (!avaliable) {
|
|
||||||
sendthread.parkNanos(1000000L);
|
|
||||||
}*/
|
|
||||||
dataPack.putTimePassport("waitForAvaliable");
|
dataPack.putTimePassport("waitForAvaliable");
|
||||||
//td.putTime("waitForAvaliable");
|
|
||||||
while(true){
|
while(true){
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw new SocketException("Socket is closed");
|
throw new SocketException("Socket is closed");
|
||||||
//System.out.println(sendmap.size());
|
|
||||||
boolean b=sendmapWindowUsed.get()<=sendWindowSize;
|
boolean b=sendmapWindowUsed.get()<=sendWindowSize;
|
||||||
//boolean b=sendmap.size()<=reallimit/MTU;
|
|
||||||
if(b)
|
if(b)
|
||||||
break;
|
break;
|
||||||
sendthread.parkNanos(1000000L);
|
sendthread.parkNanos(1000000L);
|
||||||
}
|
}
|
||||||
dataPack.putTimePassport("waitForWindow");
|
dataPack.putTimePassport("waitForWindow");
|
||||||
//td.putTime("waitForCache");
|
|
||||||
DATATPacket pack=dataPack;
|
DATATPacket pack=dataPack;
|
||||||
dataPack=null;
|
dataPack=null;
|
||||||
pack.getDataBuffer().flip();
|
pack.getDataBuffer().flip();
|
||||||
//System.out.println(pack.getDataBuffer());
|
|
||||||
//cacheCreateTime=System.nanoTime();
|
|
||||||
//td.putTime("flipBuffer");
|
|
||||||
spdlmt.transmit(pack.getDataBuffer().limit());
|
spdlmt.transmit(pack.getDataBuffer().limit());
|
||||||
socketMonitor.getOutTrafficAL().addAndGet(pack.getDataBuffer().limit());
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
socketMonitor.getOutPacketCounterAL().incrementAndGet();
|
DATATPacket prv= sendmap.put(pack.getNumber(),pack);
|
||||||
controller.getDatatMonitor().getOutTrafficAL().addAndGet(pack.getDataBuffer().limit());
|
long wu=sendmapWindowUsed.addAndGet((int) (pack.getTotalLength()+HEADER_CALIBRATE));
|
||||||
controller.getDatatMonitor().getOutPacketCounterAL().incrementAndGet();
|
if(prv!=null) {
|
||||||
//td.putTime("doStatistic");
|
wu=sendmapWindowUsed.addAndGet((int) (-(prv.getTotalLength()+HEADER_CALIBRATE)));
|
||||||
|
}
|
||||||
|
algorithm.setCurrentWindowUsed(wu );
|
||||||
|
if(debug)
|
||||||
|
System.out.println("windowused:"+wu);
|
||||||
|
|
||||||
|
|
||||||
|
socketMonitor.getOutTrafficAL().add(pack.getDataBuffer().limit());
|
||||||
|
socketMonitor.getOutPacketCounterAL().add(1);
|
||||||
|
controller.getDatatMonitor().getOutTrafficAL().add(pack.getDataBuffer().limit());
|
||||||
|
controller.getDatatMonitor().getOutPacketCounterAL().add(1);
|
||||||
|
|
||||||
pack.setPriority(5);
|
pack.setPriority(5);
|
||||||
pack.resendtimer=System.nanoTime();
|
pack.resendtimer=System.nanoTime();
|
||||||
socketRawMonitor.getOutTrafficAL().addAndGet(pack.getLength());
|
socketRawMonitor.getOutTrafficAL().add(pack.getTotalLength());
|
||||||
controller.sendPacketToAddress(remoteaddr,0,pack);
|
controller.sendPacketToAddress(remoteaddr,0,pack);
|
||||||
//td.putTime("doSend");
|
|
||||||
/* sendmaplock.readLock().lock();
|
|
||||||
try{*/
|
|
||||||
DATATPacket prv= sendmap.put(pack.getNumber(),pack);
|
|
||||||
sendmapWindowUsed.addAndGet((int) (pack.getLength()+HEADER_CALIBRATE));
|
|
||||||
if(prv!=null)
|
|
||||||
sendmapWindowUsed.addAndGet((int) (-(prv.getLength()+HEADER_CALIBRATE)));
|
|
||||||
//System.out.println("PUSH:"+pack);
|
|
||||||
/*}finally {
|
|
||||||
sendmaplock.readLock().unlock();
|
|
||||||
}*/
|
|
||||||
//td.putTime("addToList");
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//td.putTime("newPacket");
|
|
||||||
//td.print();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1066,12 +1060,14 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
DATATPacket pack=new DATATPacket(localport, port, outputcount++,MTU);
|
DATATPacket pack=new DATATPacket(localport, port, outputcount++,MTU);
|
||||||
pack.setPriority(5);
|
pack.setPriority(5);
|
||||||
pack.getDataBuffer(). flip();
|
pack.getDataBuffer(). flip();
|
||||||
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
controller.sendPacketToAddress(remoteaddr,0,pack);
|
controller.sendPacketToAddress(remoteaddr,0,pack);
|
||||||
|
});
|
||||||
/*sendmaplock.readLock().lock();
|
/*sendmaplock.readLock().lock();
|
||||||
try{*/
|
try{*/
|
||||||
pack.resendtimer=System.nanoTime();
|
pack.resendtimer=System.nanoTime();
|
||||||
sendmap.put(pack.getNumber(),pack);
|
sendmap.put(pack.getNumber(),pack);
|
||||||
sendmapWindowUsed.addAndGet((int) (pack.getLength()+HEADER_CALIBRATE));
|
sendmapWindowUsed.addAndGet((int) (pack.getTotalLength()+HEADER_CALIBRATE));
|
||||||
/*}finally {
|
/*}finally {
|
||||||
sendmaplock.readLock().unlock();
|
sendmaplock.readLock().unlock();
|
||||||
}*/
|
}*/
|
||||||
@@ -1173,11 +1169,11 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
@Override
|
@Override
|
||||||
protected void close() throws IOException {
|
protected void close() throws IOException {
|
||||||
close0(true);
|
close0(true);
|
||||||
|
|
||||||
//new Exception().printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close0(boolean b) throws IOException {
|
private void close0(boolean b) throws IOException {
|
||||||
|
|
||||||
|
//new Exception().printStackTrace();
|
||||||
if ( !isClosed()) {
|
if ( !isClosed()) {
|
||||||
closed = true;
|
closed = true;
|
||||||
|
|
||||||
@@ -1185,12 +1181,11 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl
|
|||||||
sendCheckTask.cancel();
|
sendCheckTask.cancel();
|
||||||
flowControlTask.cancel();
|
flowControlTask.cancel();
|
||||||
if(b)
|
if(b)
|
||||||
if(remoteaddr!=null)
|
if(remoteaddr!=null) {
|
||||||
try {
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
|
|
||||||
controller.sendPacketToAddress(remoteaddr,0, new RSTPacket(super.localport, super.port),
|
controller.sendPacketToAddress(remoteaddr,0, new RSTPacket(super.localport, super.port),
|
||||||
2);
|
2);
|
||||||
} catch (NoRouteToHostException e) {
|
});
|
||||||
}
|
}
|
||||||
controller.getStreamPortBinder().disconnect(this);
|
controller.getStreamPortBinder().disconnect(this);
|
||||||
if(portp!=null) {
|
if(portp!=null) {
|
||||||
@@ -1496,7 +1491,8 @@ public void associateSocketChannel(SocketChannel b) throws IOException{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(Inet6Address from, KLALBPacket u) {
|
public void accept(Inet6Address from,NetworkPacket np) {
|
||||||
|
KLALBPacket u=(KLALBPacket) np;
|
||||||
try {
|
try {
|
||||||
//System.out.println(this+" "+u);
|
//System.out.println(this+" "+u);
|
||||||
switch (u.getType()) {
|
switch (u.getType()) {
|
||||||
@@ -1544,14 +1540,14 @@ public void associateSocketChannel(SocketChannel b) throws IOException{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void acceptDATA(Inet6Address from, DATATPacket dtp) throws BindException, IOException {
|
private void acceptDATA(Inet6Address from, DATATPacket dtp) throws BindException, IOException {
|
||||||
socketRawMonitor.getInTrafficAL().addAndGet(dtp.getLength());
|
socketRawMonitor.getInTrafficAL().add(dtp.getTotalLength());
|
||||||
if(isListening()) {
|
if(isListening()) {
|
||||||
if(dtp.getNumber()==0) {
|
if(dtp.getNumber()==0) {
|
||||||
backlogQueuelock.lock();
|
backlogQueuelock.lock();
|
||||||
try{
|
try{
|
||||||
|
|
||||||
//controller.getStreamPortBinder().checkIsConnected(new Pair);
|
//controller.getStreamPortBinder().checkIsConnected(new Pair);
|
||||||
InetSocketAddress is=new InetSocketAddress(from, dtp.getSport());
|
InetSocketAddress is=new InetSocketAddress(from, dtp.getSrcPort());
|
||||||
AtomicBoolean ab=new AtomicBoolean(true);
|
AtomicBoolean ab=new AtomicBoolean(true);
|
||||||
for (Iterator iterator = backlogQueue.iterator(); iterator.hasNext();) {
|
for (Iterator iterator = backlogQueue.iterator(); iterator.hasNext();) {
|
||||||
Object[] objects = (Object[]) iterator.next();
|
Object[] objects = (Object[]) iterator.next();
|
||||||
@@ -1561,7 +1557,7 @@ public void associateSocketChannel(SocketChannel b) throws IOException{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ab.get()) {
|
if(ab.get()) {
|
||||||
if(controller.getStreamPortBinder().checkIsConnect(this,new InetSocketAddress(from, dtp.getSport()))) {
|
if(controller.getStreamPortBinder().checkIsConnect(this,new InetSocketAddress(from, dtp.getSrcPort()))) {
|
||||||
ab.set(false);
|
ab.set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1572,8 +1568,10 @@ public void associateSocketChannel(SocketChannel b) throws IOException{
|
|||||||
/* controller.sendPacketToAddress(from.getRemoteVaddr(), new ACKTPacket(dtp.getDport(), dtp.getSport(),dtp.getNumber(),true,0),
|
/* controller.sendPacketToAddress(from.getRemoteVaddr(), new ACKTPacket(dtp.getDport(), dtp.getSport(),dtp.getNumber(),true,0),
|
||||||
0,2);*/
|
0,2);*/
|
||||||
}else {
|
}else {
|
||||||
controller.sendPacketToAddress(from,0, new RSTPacket(dtp.getDport(), dtp.getSport()),
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
|
controller.sendPacketToAddress(from,0, new RSTPacket(dtp.getDstPort(), dtp.getSrcPort()),
|
||||||
2);
|
2);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1581,14 +1579,17 @@ public void associateSocketChannel(SocketChannel b) throws IOException{
|
|||||||
backlogQueuelock.unlock();
|
backlogQueuelock.unlock();
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
controller.sendPacketToAddress(from,0, new RSTPacket(dtp.getDport(), dtp.getSport()),
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
|
controller.sendPacketToAddress(from,0, new RSTPacket(dtp.getDstPort(), dtp.getSrcPort()),
|
||||||
2);
|
2);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
//System.out.println(dtp.isCE());
|
//System.out.println(dtp.isCE());
|
||||||
controller.sendPacketToAddress(from,0, new ACKTPacket(dtp.getDport(), dtp.getSport(), dtp.getNumber(),
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
getAvaliableRcvWindow(),dtp.isCE(),socketMonitor.getInSpeedMax(),dtp.getSendcount()), 1);
|
controller.sendPacketToAddress(from,0, new ACKTPacket(dtp.getDstPort(), dtp.getSrcPort(), dtp.getNumber(),
|
||||||
|
getAvaliableRcvWindow(),dtp.isCE(),socketMonitor.getInSpeedAvg(),dtp.getSendcount()), 1);
|
||||||
|
});
|
||||||
boolean added=false;
|
boolean added=false;
|
||||||
|
|
||||||
long number=dtp.getNumber();
|
long number=dtp.getNumber();
|
||||||
@@ -1624,138 +1625,47 @@ public void associateSocketChannel(SocketChannel b) throws IOException{
|
|||||||
|
|
||||||
private void acceptACK(Inet6Address from, ACKTPacket ackt) throws IOException {
|
private void acceptACK(Inet6Address from, ACKTPacket ackt) throws IOException {
|
||||||
if(isListening()) {
|
if(isListening()) {
|
||||||
controller.sendPacketToAddress(from,0, new RSTPacket(ackt.getDport(), ackt.getSport()),
|
HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||||||
|
controller.sendPacketToAddress(from,0, new RSTPacket(ackt.getDstPort(), ackt.getSrcPort()),
|
||||||
2);
|
2);
|
||||||
|
});
|
||||||
}else {
|
}else {
|
||||||
peerAvaliableRcvWindow = ackt.getAvaliableRcvWindow();
|
peerAvaliableRcvWindow = ackt.getAvaliableRcvWindow();
|
||||||
updateWindowSize();
|
updateWindowSize();
|
||||||
|
long bwrcv=ackt.getRcvSpeed();
|
||||||
|
if(debug)
|
||||||
|
System.out.println("bwrcv:"+bwrcv);
|
||||||
|
algorithm.setCurrentBandwidth(bwrcv);
|
||||||
|
|
||||||
rcvSpeed=ackt.getRcvSpeed();
|
|
||||||
|
|
||||||
/*if(rcvSpeed>=congressSpeed) {
|
|
||||||
congressSpeed=rcvSpeed;
|
|
||||||
}else {
|
|
||||||
congressSpeed=(congressSpeed*99+rcvSpeed)/100;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
requestSpeed=(long) (Math.max(MIN_LIMIT_SPEED, rcvSpeed)*congressFactor);
|
|
||||||
|
|
||||||
|
|
||||||
if(portp!=null) {
|
|
||||||
if(requestSpeed>requestSpeedOld*1.01||requestSpeed<requestSpeedOld*0.99) {
|
|
||||||
updateBandwidthReq(requestSpeed);
|
|
||||||
requestSpeedOld=requestSpeed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//System.out.println(spdlmt.getLimitspeed()/1024+"K "+ackt.getRcvSpeed()/1024+"K");
|
|
||||||
DATATPacket kl=null;
|
DATATPacket kl=null;
|
||||||
|
|
||||||
|
|
||||||
kl=sendmap.remove(ackt.getNumber());
|
kl=sendmap.remove(ackt.getNumber());
|
||||||
if(kl!=null) {
|
if(kl!=null) {
|
||||||
sendmapWindowUsed.addAndGet((int) (-(kl.getLength()+HEADER_CALIBRATE)));
|
long wu= sendmapWindowUsed.addAndGet((int) (-(kl.getTotalLength()+HEADER_CALIBRATE)));
|
||||||
|
if(debug)
|
||||||
|
System.out.println("windowused:"+wu);
|
||||||
|
algorithm.setCurrentWindowUsed(wu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(kl!=null) {
|
if(kl!=null) {
|
||||||
/* if(ackt.isCongress()) {
|
|
||||||
congressFactor=1.5;
|
|
||||||
int cachesizeold,cachesizenew;
|
|
||||||
do {
|
|
||||||
cachesizeold=congresscachesize.get();
|
|
||||||
cachesizenew=cachesizeold- kl.getSize()/2;
|
|
||||||
if(cachesizenew<8192) {
|
|
||||||
cachesizenew=8192;
|
|
||||||
}
|
|
||||||
|
|
||||||
}while(congresscachesize.compareAndSet(cachesizeold, cachesizenew));
|
|
||||||
//System.out.println(reallimit+" -8192");
|
|
||||||
|
|
||||||
}else {
|
|
||||||
int cachesizeold,cachesizenew;
|
|
||||||
do {
|
|
||||||
cachesizeold=congresscachesize.get();
|
|
||||||
cachesizenew=cachesizeold+kl.getSize()/16;
|
|
||||||
long swu=sendmapWindowUsed.get()*2L;
|
|
||||||
if(cachesizenew>swu) {
|
|
||||||
cachesizenew=(int) swu;
|
|
||||||
}
|
|
||||||
|
|
||||||
}while(congresscachesize.compareAndSet(cachesizeold, cachesizenew));
|
|
||||||
|
|
||||||
//System.out.println(reallimit+" +1024");
|
|
||||||
|
|
||||||
}*/
|
|
||||||
if(ackt.isCongress()) {
|
|
||||||
congressFactor=1.5;
|
|
||||||
if(congressWindowSize>65535) {
|
|
||||||
congressWindowSize-=(kl.getSize()+HEADER_CALIBRATE)/8;
|
|
||||||
updateWindowSize();
|
|
||||||
//System.out.println(reallimit+" -8192");
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
if(sendmapWindowUsed.get()*2L>=congressWindowSize&&congressWindowSize<=outputchachesize) {
|
|
||||||
congressWindowSize+=(kl.getSize()+HEADER_CALIBRATE)/32;
|
|
||||||
updateWindowSize();
|
|
||||||
//System.out.println(reallimit+" +1024");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//controller.removeFromSend(from.getRemoteVaddr(),kl);
|
|
||||||
if(kl.getSendCounter()==1) {
|
if(kl.getSendCounter()==1) {
|
||||||
long RTTC=ackt.getRcvtime()- kl.getSndtime();
|
long RTTC=ackt.getRcvtime()- kl.getSndtime();
|
||||||
if(RTTC<=RTTMin) {
|
algorithm.putAck(kl.getTotalLength(), RTTC,ackt.isCongress());
|
||||||
RTTMin=RTTC;
|
|
||||||
}else {
|
|
||||||
RTTMin= (RTTMin*99999+RTTC)/100000;
|
|
||||||
}
|
|
||||||
|
|
||||||
long queueing=RTTC-RTTMin;
|
|
||||||
QueueingAvg=(QueueingAvg*99999+queueing)/100000;
|
|
||||||
|
|
||||||
if(firstUpdate.compareAndSet(true, false)) {
|
|
||||||
RTTAvg=RTTC;
|
|
||||||
RTTVar=RTTC/2;
|
|
||||||
|
|
||||||
}else {
|
|
||||||
RTTVar=(RTTVar*3+Math.abs(RTTAvg-RTTC))/4;
|
|
||||||
RTTAvg= (RTTAvg*7+RTTC)/8;
|
|
||||||
}
|
|
||||||
RTO=RTTAvg+Math.max(MIN_RTTVAR, RTTVar*4);//RTTVar*4
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*if(RTTC>RTO) {
|
|
||||||
congressFactor=Math.min( 0.9,congressFactor);
|
|
||||||
}else {
|
|
||||||
if(congressFactor<1.1)
|
|
||||||
congressFactor+=0.001;
|
|
||||||
} */
|
|
||||||
|
|
||||||
|
|
||||||
//System.out.println(congressFactor);
|
|
||||||
//spdlmt.setLimitspeed(1024*1024);
|
|
||||||
//reallimit=Math.max(MTU*2,(int) (congressSpeed*RTTMin*4/1000000000L));
|
|
||||||
//System.out.println(reallimit/MTU);
|
|
||||||
/*long nspd=(long) (congressSpeed*congressFactor);
|
|
||||||
spdlmt.setLimitspeed(Math.max(nspd,MIN_LIMIT_SPEED));*/
|
|
||||||
|
|
||||||
|
|
||||||
// System.out.println("RwqSpeed:"+(requestSpeed/1024)+"K MaxSpeed:"+(congressSpeed/1024)+"K LimitSpeed:"+(spdlmt.getLimitspeed()/1024)+"K");
|
|
||||||
//System.out.println("RTTMin:"+RTTMin/1000000L+"ms RTTAvg:"+RTTAvg/1000000L+"ms");
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//kl.dispose();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//ackt.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateWindowSize() {
|
private void updateWindowSize() {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.kne.cloud.network.klalb;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.Channel;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
public class MonitoredChannel implements Channel,ReadableByteChannel ,WritableByteChannel{
|
||||||
|
|
||||||
|
private Channel channel;
|
||||||
|
private AtomicLong[] totalIn;
|
||||||
|
private AtomicLong[] totalOut;
|
||||||
|
|
||||||
|
public MonitoredChannel (Channel channel,AtomicLong[] totalIn,AtomicLong[] totalOut) {
|
||||||
|
this.channel=channel;
|
||||||
|
this.totalIn=totalIn;
|
||||||
|
this.totalOut=totalOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Channel getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return channel.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
channel.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int write(ByteBuffer src) throws IOException {
|
||||||
|
int count=((WritableByteChannel)channel).write(src);
|
||||||
|
for(AtomicLong x:totalOut)
|
||||||
|
x.addAndGet(count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(ByteBuffer dst) throws IOException {
|
||||||
|
int count=((ReadableByteChannel)channel).read(dst);
|
||||||
|
if(count!=-1) {
|
||||||
|
for(AtomicLong x:totalIn)
|
||||||
|
x.incrementAndGet();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,11 +4,12 @@ import java.io.FilterInputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
|
|
||||||
public class MonitoredInputStream extends FilterInputStream {
|
public class MonitoredInputStream extends FilterInputStream {
|
||||||
|
|
||||||
private AtomicLong[] total;
|
private LongAdder[] total;
|
||||||
public MonitoredInputStream(InputStream inputStream,AtomicLong... v) {
|
public MonitoredInputStream(InputStream inputStream,LongAdder... v) {
|
||||||
super(inputStream);
|
super(inputStream);
|
||||||
this.total=v;
|
this.total=v;
|
||||||
}
|
}
|
||||||
@@ -17,8 +18,8 @@ public class MonitoredInputStream extends FilterInputStream {
|
|||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
int v=in.read();
|
int v=in.read();
|
||||||
if(v!=-1) {
|
if(v!=-1) {
|
||||||
for(AtomicLong x:total)
|
for(LongAdder x:total)
|
||||||
x.incrementAndGet();
|
x.add(1);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@@ -27,8 +28,8 @@ public class MonitoredInputStream extends FilterInputStream {
|
|||||||
public int read(byte[] b) throws IOException {
|
public int read(byte[] b) throws IOException {
|
||||||
int v=in.read(b);
|
int v=in.read(b);
|
||||||
if(v!=-1) {
|
if(v!=-1) {
|
||||||
for(AtomicLong x:total)
|
for(LongAdder x:total)
|
||||||
x.addAndGet(v);
|
x.add(v);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@@ -37,8 +38,8 @@ public class MonitoredInputStream extends FilterInputStream {
|
|||||||
public int read(byte[] b, int off, int len) throws IOException {
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
int v=in.read(b, off, len);
|
int v=in.read(b, off, len);
|
||||||
if(v!=-1) {
|
if(v!=-1) {
|
||||||
for(AtomicLong x:total)
|
for(LongAdder x:total)
|
||||||
x.addAndGet(v);
|
x.add(v);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import java.io.FilterOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
|
|
||||||
public class MonitoredOutputStream extends FilterOutputStream {
|
public class MonitoredOutputStream extends FilterOutputStream {
|
||||||
|
|
||||||
private AtomicLong[] total;
|
private LongAdder[] total;
|
||||||
public MonitoredOutputStream(OutputStream outputStream,AtomicLong ...v) {
|
public MonitoredOutputStream(OutputStream outputStream,LongAdder ...v) {
|
||||||
super(outputStream);
|
super(outputStream);
|
||||||
this.total=v;
|
this.total=v;
|
||||||
}
|
}
|
||||||
@@ -16,22 +17,22 @@ public class MonitoredOutputStream extends FilterOutputStream {
|
|||||||
@Override
|
@Override
|
||||||
public void write(int b) throws IOException {
|
public void write(int b) throws IOException {
|
||||||
out.write(b);
|
out.write(b);
|
||||||
for(AtomicLong x:total)
|
for(LongAdder x:total)
|
||||||
x.incrementAndGet();
|
x.add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] b) throws IOException {
|
public void write(byte[] b) throws IOException {
|
||||||
out.write(b);
|
out.write(b);
|
||||||
for(AtomicLong x:total)
|
for(LongAdder x:total)
|
||||||
x.addAndGet(b.length);
|
x.add(b.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
out.write(b, off, len);
|
out.write(b, off, len);
|
||||||
for(AtomicLong x:total)
|
for(LongAdder x:total)
|
||||||
x.addAndGet(len);
|
x.add(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ public class NACKTPacket extends KLALBPacket implements PortPacket{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "NACKT "+getSport()+"->"+getDport()+" "+getNumber()+"[]";
|
return "NACKT "+getSrcPort()+"->"+getDstPort()+" "+getNumber()+"[]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSport() {
|
public int getSrcPort() {
|
||||||
return klalbHeader.getInt(1);
|
return klalbHeader.getInt(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDport() {
|
public int getDstPort() {
|
||||||
return klalbHeader.getInt(5);
|
return klalbHeader.getInt(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class PONGPacket extends KLALBPacket {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLength() {
|
public long getTotalLength() {
|
||||||
return HEADER_LENGTH;
|
return HEADER_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import java.net.Inet6Address;
|
|||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public interface KLALBPacketConsumer extends BiConsumer<Inet6Address, KLALBPacket> {
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
|
||||||
}
|
public interface PacketConsumer extends BiConsumer<Inet6Address, NetworkPacket> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,6 +18,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
|
|
||||||
import com.google.gson.internal.Pair;
|
import com.google.gson.internal.Pair;
|
||||||
|
|
||||||
public class PortBinder {
|
public class PortBinder {
|
||||||
@@ -58,7 +60,7 @@ public class PortBinder {
|
|||||||
if(portn==portnod) {
|
if(portn==portnod) {
|
||||||
cnt++;
|
cnt++;
|
||||||
if(cnt>1) {
|
if(cnt>1) {
|
||||||
throw new BindException("can't alloc port");
|
throw new BindException("can't alloc port");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean flag=true;
|
boolean flag=true;
|
||||||
@@ -105,7 +107,7 @@ public class PortBinder {
|
|||||||
connectMaplock.writeLock().unlock();
|
connectMaplock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void disconnect(BindableKLALBPacketConsumer ks) throws BindException {
|
public void disconnect(BindableKLALBPacketConsumer ks) {
|
||||||
connectMaplock.writeLock().lock();
|
connectMaplock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
removeAsValue(connectMap, ks);
|
removeAsValue(connectMap, ks);
|
||||||
@@ -122,7 +124,7 @@ public class PortBinder {
|
|||||||
listenMaplock.writeLock().unlock();
|
listenMaplock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void unlisten(BindableKLALBPacketConsumer ks) throws BindException {
|
public void unlisten(BindableKLALBPacketConsumer ks) {
|
||||||
/*System.out.println(listenMap);
|
/*System.out.println(listenMap);
|
||||||
new RuntimeException("!").printStackTrace();*/
|
new RuntimeException("!").printStackTrace();*/
|
||||||
listenMaplock.writeLock().lock();
|
listenMaplock.writeLock().lock();
|
||||||
@@ -205,35 +207,35 @@ public class PortBinder {
|
|||||||
return b;
|
return b;
|
||||||
}*/
|
}*/
|
||||||
public boolean distributePacketToConsumer(Inet6Address srcAddr,PortPacket packet) {
|
public boolean distributePacketToConsumer(Inet6Address srcAddr,PortPacket packet) {
|
||||||
InetSocketAddress local=new InetSocketAddress(controller.getSelf().getAddress(), packet.getDport());
|
InetSocketAddress local=new InetSocketAddress(controller.getSelf().getAddress(), packet.getDstPort());
|
||||||
InetSocketAddress remote=new InetSocketAddress(srcAddr, packet.getSport());
|
InetSocketAddress remote=new InetSocketAddress(srcAddr, packet.getSrcPort());
|
||||||
BindableKLALBPacketConsumer bkc=connectMap.get(new Pair<InetSocketAddress, InetSocketAddress>(local, remote));
|
BindableKLALBPacketConsumer bkc=connectMap.get(new Pair<InetSocketAddress, InetSocketAddress>(local, remote));
|
||||||
if(bkc!=null) {
|
if(bkc!=null) {
|
||||||
bkc.accept(srcAddr, (KLALBPacket) packet);
|
bkc.accept(srcAddr, (NetworkPacket) packet);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
InetSocketAddress localany=new InetSocketAddress(ANYLA, packet.getDport());
|
InetSocketAddress localany=new InetSocketAddress(ANYLA, packet.getDstPort());
|
||||||
bkc=connectMap.get(new Pair<InetSocketAddress, InetSocketAddress>(localany, remote));
|
bkc=connectMap.get(new Pair<InetSocketAddress, InetSocketAddress>(localany, remote));
|
||||||
if(bkc!=null) {
|
if(bkc!=null) {
|
||||||
bkc.accept(srcAddr, (KLALBPacket) packet);
|
bkc.accept(srcAddr, (NetworkPacket) packet);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bkc=listenMap.get(local);
|
bkc=listenMap.get(local);
|
||||||
if(bkc!=null) {
|
if(bkc!=null) {
|
||||||
bkc.accept(srcAddr, (KLALBPacket) packet);
|
bkc.accept(srcAddr, (NetworkPacket) packet);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bkc=listenMap.get(localany);
|
bkc=listenMap.get(localany);
|
||||||
if(bkc!=null) {
|
if(bkc!=null) {
|
||||||
bkc.accept(srcAddr, (KLALBPacket) packet);
|
bkc.accept(srcAddr, (NetworkPacket) packet);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public boolean checkIsBind(KLALBVirtualSocketImpl klalbVirtualSocketImpl) {
|
public boolean checkIsBind(BindableKLALBPacketConsumer klalbVirtualSocketImpl) {
|
||||||
return bindMap.containsValue(klalbVirtualSocketImpl);
|
return bindMap.containsValue(klalbVirtualSocketImpl);
|
||||||
}
|
}
|
||||||
public boolean checkIsConnect(BindableKLALBPacketConsumer kservers,InetSocketAddress isaf) throws BindException {
|
public boolean checkIsConnect(BindableKLALBPacketConsumer kservers,InetSocketAddress isaf) throws BindException {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.kne.cloud.network.klalb;
|
|||||||
|
|
||||||
public interface PortPacket {
|
public interface PortPacket {
|
||||||
|
|
||||||
public int getSport();
|
public int getSrcPort();
|
||||||
|
|
||||||
public int getDport();
|
public int getDstPort();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,17 +20,17 @@ public class RSTPacket extends KLALBPacket implements PortPacket{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getSport() {
|
public int getSrcPort() {
|
||||||
return klalbHeader.getInt(1);
|
return klalbHeader.getInt(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDport() {
|
public int getDstPort() {
|
||||||
return klalbHeader.getInt(5);
|
return klalbHeader.getInt(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RST "+getSport()+"->"+getDport();
|
return "RST "+getSrcPort()+"->"+getDstPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,29 @@
|
|||||||
package org.kne.cloud.network.klalb;
|
package org.kne.cloud.network.klalb;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
|
|
||||||
public class SendItem {
|
public class SendItem<T extends NetworkPacket> {
|
||||||
|
|
||||||
private IPv6Packet packet;
|
private long packetLength;
|
||||||
|
private T packet;
|
||||||
private long sendtime=System.nanoTime();
|
private long sendtime=System.nanoTime();
|
||||||
|
|
||||||
public SendItem(IPv6Packet packet) {
|
public SendItem(T packet) {
|
||||||
this.packet=packet;
|
this.packet=packet;
|
||||||
|
this.packetLength=packet.getTotalLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPv6Packet getPacket() {
|
public T getPacket() {
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getSendtime() {
|
public long getSendtime() {
|
||||||
return sendtime;
|
return sendtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getPacketLength() {
|
||||||
|
return packetLength;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||