package org.kne.cloud.network.perf; import java.io.IOException; import java.net.Inet6Address; import java.net.InetAddress; import java.nio.channels.UnresolvedAddressException; import java.util.Objects; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.locks.LockSupport; import org.kne.cloud.clock.AdjustedNanoClock; import org.kne.cloud.network.MultipurposeSocketAddress; import org.kne.cloud.network.SpeedLimiter; import org.kne.cloud.network.ThreadTool; import org.kne.cloud.network.ipv6.IPv6Packet; import org.kne.cloud.network.ipv6.Inet6AddressGroup; import org.kne.cloud.network.klalb.ADDRPacket; import org.kne.cloud.network.klalb.ADDRREQPacket; import org.kne.cloud.network.klalb.BWINFPacket; import org.kne.cloud.network.klalb.IPv6OverKLALBPacket; import org.kne.cloud.network.klalb.KLALBPacket; import org.kne.cloud.network.klalb.KLALBPacketLink; import org.kne.cloud.network.klalb.KLALBUtils; import org.kne.cloud.network.klalb.PINGPacket; import org.kne.cloud.network.klalb.PONGPacket; import org.kne.cloud.network.klalb.VADDRACKPacket; import org.kne.cloud.network.klalb.VADDRPacket; import org.kne.cloud.network.klalb.VADDRREQPacket; import org.kne.cloud.network.monitor.MonitorData; import org.kne.cloud.network.monitor.QueueingMonitorDataImpl; public class Kperf implements Runnable{ private KperfReports reports; private ConcurrentLinkedQueue IsendDequeList = new ConcurrentLinkedQueue(); //private PriorityBlockingQueue sendDequeList = new PriorityBlockingQueue(); private static final boolean debug = true; private static final boolean showpacket = false; private volatile AdjustedNanoClock adjnc = new AdjustedNanoClock(); private MultipurposeSocketAddress targetAddress; private MultipurposeSocketAddress bindAddress; private volatile boolean connected=false; private volatile KLALBPacketLink link; private QueueingMonitorDataImpl monitor=new QueueingMonitorDataImpl(); private volatile boolean closed = false; private volatile Thread tlock; public Kperf(MultipurposeSocketAddress targetAddress,MultipurposeSocketAddress bindAddress) { Objects.requireNonNull(targetAddress); this.targetAddress=targetAddress; this.bindAddress=bindAddress; } public Kperf(MultipurposeSocketAddress targetAddress) { this(targetAddress,new MultipurposeSocketAddress("[::0]:0")); } public Kperf(KLALBPacketLink link) { Objects.requireNonNull(link); this.link=link; } public KperfReports getReports() { return reports; } public void setReports(KperfReports reports) { this.reports = reports; } private SpeedLimiter test = new SpeedLimiter(MIN_SPEED,10000000L); private static long MIN_SPEED=64*1024L; private SpeedLimiter congress = new SpeedLimiter(10000000L); private long congressSpeed = 0; private double loadPercent = 1.01; KLALBPacket testPacket=null; private long starttime=System.nanoTime(); long totaltime=1000; long usedtime=0; //kperf {KLALB_Stream}[2486:1:f189:7589:f1f7:6f5e:b2eb:1]:4564 //kperf {KLALB_Stream}[2486:1::8888]:4564 @Override public void run() { Thread tc = ThreadTool.makeVDaemonThreadIfSupport("测速控制线程", () -> { final int wtimes=5; totaltime=(20*1000*1+20*1000*4+wtimes*1000*5)*1000000L; starttime=System.nanoTime(); System.out.println("测速开始!"); try { long startTime; System.out.println("测试1/5:延迟测试"); test.setLimitspeed(0); startTime=System.nanoTime(); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("上传延迟:%.3fms 下载延迟:%.3fms\n", monitor.getOutDelay()/1000000.0,monitor.getInDelay()/1000000.0); Thread.sleep(1000); updateUsedTime(); } System.out.printf("上传延迟 最小:%.3fms 平均:%.3fms 抖动:%.3fms\n",monitor.getOutDelayMin()/1000000.0,monitor.getOutDelayAvg()/1000000.0,monitor.getOutJitter()/1000000.0); System.out.printf("下载延迟 最小:%.3fms 平均:%.3fms 抖动:%.3fms\n",monitor.getInDelayMin()/1000000.0,monitor.getInDelayAvg()/1000000.0,monitor.getInJitter()/1000000.0); if(reports!=null) { monitor.setOutDelay(monitor.getOutDelayAvg()); monitor.setInDelay(monitor.getInDelayAvg()); } System.out.println("等待时间"+wtimes+"s"); Thread.sleep(wtimes*1000); startTime=System.nanoTime(); if(targetAddress!=null) { System.out.println("测试2/5:下载带宽测试"); test.setLimitspeed(0); testPacket=new TESTNPacket(60000); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("下载带宽:%s/s\n", KLALBUtils.convertIBUint(monitor.getInSpeedAvg())); Thread.sleep(1000); } System.out.printf("下载带宽 平均:%s/s 最大:%s/s\n",KLALBUtils.convertIBUint(monitor.getInSpeedAvg2()),KLALBUtils.convertIBUint(monitor.getInSpeedMax2())); if(reports!=null) { reports.downloadSpeedFinish(monitor.getInSpeedAvg2()); } }else { System.out.println("测试2/5:上传带宽测试"); test.setLimitspeed(1000L*1024L*1024L*1024L); testPacket=new TESTNPacket(60000); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("上传带宽:%s/s\n", KLALBUtils.convertIBUint(monitor.getOutSpeedAvg())); Thread.sleep(1000); } System.out.printf("上传带宽 平均:%s/s 最大:%s/s\n",KLALBUtils.convertIBUint(monitor.getOutSpeedAvg2()),KLALBUtils.convertIBUint(monitor.getOutSpeedMax2())); if(reports!=null) { reports.uploadSpeedFinish(monitor.getOutSpeedAvg2()); } } System.out.println("等待时间"+wtimes+"s"); Thread.sleep(wtimes*1000); startTime=System.nanoTime(); if(targetAddress!=null) { System.out.println("测试3/5:上传带宽测试"); test.setLimitspeed(1000L*1024L*1024L*1024L); testPacket=new TESTNPacket(60000); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("上传带宽:%s/s\n", KLALBUtils.convertIBUint(monitor.getOutSpeedAvg())); Thread.sleep(1000); } System.out.printf("上传带宽 平均:%s/s 最大:%s/s\n",KLALBUtils.convertIBUint(monitor.getOutSpeedAvg2()),KLALBUtils.convertIBUint(monitor.getOutSpeedMax2())); if(reports!=null) { reports.uploadSpeedFinish(monitor.getOutSpeedAvg2()); } }else { System.out.println("测试3/5:下载带宽测试"); test.setLimitspeed(0); testPacket=new TESTNPacket(60000); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("下载带宽:%s/s\n", KLALBUtils.convertIBUint(monitor.getInSpeedAvg())); Thread.sleep(1000); } System.out.printf("下载带宽 平均:%s/s 最大:%s/s\n",KLALBUtils.convertIBUint(monitor.getInSpeedAvg2()),KLALBUtils.convertIBUint(monitor.getInSpeedMax2())); if(reports!=null) { reports.downloadSpeedFinish(monitor.getInSpeedAvg2()); } } System.out.println("等待时间"+wtimes+"s"); Thread.sleep(wtimes*1000); startTime=System.nanoTime(); if(targetAddress!=null) { System.out.println("测试4/5:下载包转发率测试"); test.setLimitspeed(0); testPacket=new TEST1Packet(); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("下载包转发率:%sPPS\n", KLALBUtils.convertUintDefalut(monitor.getInPPS())); Thread.sleep(1000); } if(reports!=null) { reports.downloadPPSFinish(monitor.getInPPSAvg()); } }else { System.out.println("测试4/5:上传包转发率测试"); test.setLimitspeed(1000L*1024L*1024L*1024L); testPacket=new TEST1Packet(); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("上传包转发率:%sPPS\n", KLALBUtils.convertUintDefalut(monitor.getOutPPS())); Thread.sleep(1000); } if(reports!=null) { reports.uploadPPSFinish(monitor.getOutPPSAvg()); } } System.out.println("等待时间"+wtimes+"s"); Thread.sleep(wtimes*1000); startTime=System.nanoTime(); if(targetAddress!=null) { System.out.println("测试5/5:上传包转发率测试"); test.setLimitspeed(1000L*1024L*1024L*1024L); testPacket=new TEST1Packet(); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("上传包转发率:%sPPS\n", KLALBUtils.convertUintDefalut(monitor.getOutPPS())); Thread.sleep(1000); } if(reports!=null) { reports.uploadPPSFinish(monitor.getOutPPSAvg()); } }else { System.out.println("测试5/5:下载包转发率测试"); test.setLimitspeed(0); testPacket=new TEST1Packet(); for (int i = 0; i < 20; i++) { System.out.printf("%.2fs\t", (System.nanoTime()- startTime)/1000000000.0); System.out.printf("下载包转发率:%sPPS\n", KLALBUtils.convertUintDefalut(monitor.getInPPS())); Thread.sleep(1000); } if(reports!=null) { reports.downloadPPSFinish(monitor.getInPPSAvg()); } } System.out.println("等待时间"+wtimes+"s"); Thread.sleep(wtimes*1000); } catch (InterruptedException e) { //System.out.println("测速被中断!"); }finally { close(); if(reports!=null) reports.testFinish(); System.out.println("测速结束!"); } }); try { monitor.setState(MonitorData.CONNECTING); if(link==null) link=KLALBUtils.createKLALBPacketLink(bindAddress, targetAddress,false,20000); link.setSoTimeout(20000); Thread t = ThreadTool.makeVDaemonThreadIfSupport("测速发送线程", () -> { tlock = Thread.currentThread(); try { KLALBPacket kpp = null; while ((!link.isClosed()) && (!closed)) { // TimeDebugger tdb=new TimeDebugger(); // tdb.putTime("start"); if(checkBandwidthReportTime()) { writePacketToKPL(new BWINFPacket(monitor.getOutSpeedAvg(), monitor.getInSpeedAvg())); } if (checkPingTimeSleep()) { writePacketToKPL(new PINGPacket(System.nanoTime())); }else { KLALBPacket kpip = IsendDequeList.poll(); if (kpip != null) { writePacketToKPL(kpip); }else { KLALBPacket testp=testPacket; if (testp!=null&&test.checkTransmit(testp.getTotalLength())) { writePacketToKPL(testp); }else { LockSupport.parkNanos(1000000); } } } Thread.yield(); } } catch (IOException | UnresolvedAddressException e) { if (debug) e.printStackTrace(); } finally { try { link.close(); } catch (IOException e) { e.printStackTrace(); } } }); t.start(); boolean fst = true; while ((!link.isClosed()) && (!closed)) { KLALBPacket kpp = readPacketFromKPL(); if (kpp == null) { break; } switch (kpp.getType()) { case KLALBPacket.PING: sendIPacket(new PONGPacket(((PINGPacket) kpp).getTime() ,kpp.getRcvtime(), System.nanoTime())); break; case KLALBPacket.PONG: if (fst) { // coll.resetCoolingTime(); monitor.setState(MonitorData.ONLINE); connected=true; if(targetAddress!=null) { System.out.println("连接地址"+targetAddress+"成功!"); }else { System.out.println("接受地址"+link.toString()+"连接成功!"); } tc.start(); fst = false; } PONGPacket png = (PONGPacket) kpp; long ul = png.getRcvtime() - png.getTimepingsnd()-(png.getTimepongsnd()-png.getTimepingrcv()); long DsndDelayFactor0 = png.getTimepingrcv() - png.getTimepingsnd(); long DrcvDelayFactor0 = png.getRcvtime() - png.getTimepongsnd(); long DsndDelayFactor; long DrcvDelayFactor; adjnc.getLock().lock(); try { adjnc.calibrate(png.getTimepongsnd() + ul / 2 - png.getRcvtime(), ul / 2); DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta(); DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta(); if (DsndDelayFactor < 0) { if (DrcvDelayFactor < 0) { } else { adjnc.setDelta(adjnc.getDelta() + DsndDelayFactor); DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta(); DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta(); } } else { if (DrcvDelayFactor < 0) { adjnc.setDelta(adjnc.getDelta() - DrcvDelayFactor); DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta(); DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta(); } } } finally { adjnc.getLock().unlock(); } if (DsndDelayFactor >= 0 && DrcvDelayFactor >= 0) { monitor.setOutDelay(DsndDelayFactor); monitor.setInDelay(DrcvDelayFactor); monitor.setRecentPingNanoTime(png.getTimepingsnd()); //pingInterval = monitor.getLatencyAvg()+2000000L; //double load = 1 - monitor.getOutDelayMin() / (double) monitor.getOutDelay(); loadPercent =Math.max( 1.2,0.4); } LockSupport.unpark(tlock); updateUsedTime() ; if(reports!=null) reports.updateDial(monitor); break; case KLALBPacket.BWINF: BWINFPacket bwi = (BWINFPacket) kpp; if (bwi.getDownSpeed() >= congressSpeed) { congressSpeed = bwi.getDownSpeed(); } else { congressSpeed = (congressSpeed * 999 + bwi.getDownSpeed()) / 1000; } congress.setLimitspeed(Math.max(MIN_SPEED,(long) (congressSpeed * loadPercent)) ); // System.out.println(congressSpeed); break; case KLALBPacket.TESTN: break; } Thread.yield(); } } catch (IOException e) { if(monitor.getState()==MonitorData.CONNECTING) System.out.println("连接目标地址失败!"); if(debug) e.printStackTrace(); }finally { monitor.setState(MonitorData.OFFLINE); if(link!=null) { try { link.close(); } catch (IOException e) { e.printStackTrace(); } } tc.interrupt(); } } private void updateUsedTime() { usedtime=System.nanoTime()-starttime; //System.out.println(usedtime+" "+totaltime); if(reports!=null) reports.testProcess(usedtime/(double)totaltime); } private volatile long time = System.nanoTime(); private volatile long pingInterval = 10000000L; private volatile long pingIntervalSleep = 200000000L; private boolean checkPingTime() { long cu = System.nanoTime(); if (cu - time > pingInterval) { time = cu; return true; } else { return false; } } private boolean checkPingTimeSleep() { long cu = System.nanoTime(); if (cu - time > pingIntervalSleep) { time = cu; return true; } else { return false; } } private volatile long bwtime = System.nanoTime(); private volatile long bwpingInterval = 10000000L; private volatile long bwpingIntervalSleep = 100000000L; private boolean checkBandwidthReportTime(){ long cu = System.nanoTime(); if (cu - bwtime > bwpingIntervalSleep) { bwtime = cu; return true; } else { return false; } } public void close() { closed = true; monitor.setState(MonitorData.OFFLINE); try { if (link != null) link.close(); } catch (IOException e) { e.printStackTrace(); } } /*protected void sendPacket(KLALBPacket blk) { blk.markJoinqueuetime(); sendDequeList.add(blk); LockSupport.unpark(tlock); }*/ private void sendIPacket(KLALBPacket blk) { IsendDequeList.add(blk); LockSupport.unpark(tlock); } private KLALBPacket readPacketFromKPL() throws IOException { KLALBPacket packet = link.readKLALBPacket(); if (showpacket) { System.out.println("RX:" + packet); } if (packet != null) { packet.putTimePassport("received"); long length=packet.getTotalLength(); monitor.getInTrafficAL().add(length); monitor.getInPacketCounterAL().add(1); } return packet; } private void writePacketToKPL(KLALBPacket packet) throws IOException { long length=packet.getTotalLength(); monitor.getOutTrafficAL().add(length); monitor.getOutPacketCounterAL().add(1); link.writeKLALBPacket(packet); link.flush(); packet.putTimePassport("sended"); packet.printPassport(); if (showpacket) { System.err.println("TX:" + packet); } } public void startPerfing() { ThreadTool.makeVThreadIfSupport("测速接收线程" ,this).start(); } }