forked from KNEMC/KLALB
稳定性升级
This commit is contained in:
@@ -31,12 +31,17 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import org.kne.cloud.network.mport.VirtualSocketImpl;
|
||||
import org.kne.io.Data;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
public class KLALBVirtualSocketImpl extends VirtualSocketImpl {
|
||||
private KLALBController controller;
|
||||
|
||||
protected int getInputchachesize() {
|
||||
@@ -55,8 +60,19 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
this.outputchachesize = outputchachesize;
|
||||
}
|
||||
|
||||
private int inputchachesize = 5773 * 100;
|
||||
private int outputchachesize = 5773 * 100;
|
||||
private volatile int inputchachesize = LIMIT * 500;
|
||||
private volatile int outputchachesize = LIMIT * 200;
|
||||
private volatile boolean nodelay=false;
|
||||
private volatile long delaytime=1;
|
||||
|
||||
public long getDelaytime() {
|
||||
return delaytime;
|
||||
}
|
||||
|
||||
public void setDelaytime(long delaytime) {
|
||||
this.delaytime = delaytime;
|
||||
}
|
||||
|
||||
private Inet6Address bindaddr;{
|
||||
try {
|
||||
bindaddr=(Inet6Address) Inet6Address.getByName("::0");
|
||||
@@ -77,15 +93,20 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
try {
|
||||
sendlist.get(i).check(i);
|
||||
} catch (IOException e) {
|
||||
// TODO 自动生成的 catch 块
|
||||
e.printStackTrace();
|
||||
try {
|
||||
close();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private boolean succeed, refused;
|
||||
private volatile boolean succeed, refused;
|
||||
|
||||
protected boolean isListening() {
|
||||
return backlogQueue != null;
|
||||
@@ -93,7 +114,7 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
|
||||
private List<DATATPacket> inputchache = new ArrayList<>();
|
||||
private long inputcount = 0;
|
||||
private boolean avaliable = true;
|
||||
private volatile boolean avaliable = true;
|
||||
private BiConsumer<Inet6Address, KLALBPacket> packReceiver = new BiConsumer<Inet6Address, KLALBPacket>() {
|
||||
|
||||
@Override
|
||||
@@ -104,15 +125,15 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
|
||||
if (backlogQueue.offer(new InetSocketAddress(from, ((SYNTPacket) u).getSport()))) {
|
||||
controller.sendPacketToAddress(from,
|
||||
new SACKTPacket(localport, ((SYNTPacket) u).getSport()), 65537);
|
||||
new SACKTPacket(localport, ((SYNTPacket) u).getSport()), 65537,2);
|
||||
|
||||
} else {
|
||||
controller.sendPacketToAddress(from, new RSTPacket(localport, ((SYNTPacket) u).getSport()),
|
||||
65537);
|
||||
65537,2);
|
||||
}
|
||||
} else {
|
||||
controller.sendPacketToAddress(from, new RSTPacket(localport, ((SYNTPacket) u).getSport()),
|
||||
65537);
|
||||
65537,2);
|
||||
}
|
||||
} else if (u instanceof SACKTPacket) {
|
||||
if (connecting) {
|
||||
@@ -148,23 +169,34 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
if (kkb == null)
|
||||
break;
|
||||
sendDeque.add(kkb);
|
||||
synchronized (sendDeque) {
|
||||
sendDeque.notifyAll();
|
||||
|
||||
}
|
||||
inputcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
controller.sendPacketToAddress(from, new ACKTPacket(dtp.getDport(), dtp.getSport(), dtp.getNumber(),
|
||||
countInputBytes() < inputchachesize), 32768,2);
|
||||
countInputBytes() < inputchachesize), 32768,1);
|
||||
} else if (u instanceof ACKTPacket) {
|
||||
ACKTPacket ackt = (ACKTPacket) u;
|
||||
avaliable = ackt.isAvaliable();
|
||||
AtomicReference<KLALBPacket>kl=new AtomicReference<>();
|
||||
AtomicReference<DATATPacket>kl=new AtomicReference<>();
|
||||
synchronized (sendlist) {
|
||||
|
||||
sendlist.removeIf((tsk)->{
|
||||
boolean b=tsk.getPacket().getNumber()==ackt.getNumber();
|
||||
if(b)
|
||||
kl.set(tsk.getPacket());
|
||||
return b;
|
||||
});
|
||||
sendlist.notifyAll();
|
||||
}
|
||||
if(kl.get()!=null) {
|
||||
controller.removeFromSend(from,kl.get());
|
||||
DATATPacket.arrayRecycle.recycle(kl.get().getData());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@@ -177,14 +209,14 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
private int countInputBytes() {
|
||||
AtomicInteger i = new AtomicInteger(0);
|
||||
sendDeque.forEach((c) -> {
|
||||
i.addAndGet(c.getData().length);
|
||||
i.addAndGet(c.getSize());
|
||||
});
|
||||
return i.get();
|
||||
}
|
||||
private int countOutputBytes() {
|
||||
AtomicInteger i = new AtomicInteger(0);
|
||||
sendlist.forEach((c) -> {
|
||||
i.addAndGet(c.getPacket().getData().length);
|
||||
i.addAndGet(c.getPacket().getSize());
|
||||
});
|
||||
return i.get();
|
||||
}
|
||||
@@ -204,23 +236,34 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
|
||||
@Override
|
||||
public void setOption(int optID, Object value) throws SocketException {
|
||||
if(optID==SocketOptions.SO_RCVBUF) {
|
||||
switch(optID) {
|
||||
case SocketOptions.TCP_NODELAY:
|
||||
nodelay=(boolean) value;
|
||||
break;
|
||||
case SocketOptions.SO_RCVBUF:
|
||||
inputchachesize=(int) value;
|
||||
}else if(optID==SocketOptions.SO_SNDBUF) {
|
||||
break;
|
||||
case SocketOptions.SO_SNDBUF:
|
||||
outputchachesize=(int)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOption(int optID) throws SocketException {
|
||||
if(optID==SocketOptions.SO_BINDADDR) {
|
||||
return bindaddr;
|
||||
}else if(optID==SocketOptions.SO_RCVBUF) {
|
||||
switch(optID) {
|
||||
case SocketOptions.TCP_NODELAY:
|
||||
return nodelay;
|
||||
case SocketOptions.SO_RCVBUF:
|
||||
return inputchachesize;
|
||||
}else if(optID==SocketOptions.SO_SNDBUF) {
|
||||
case SocketOptions.SO_SNDBUF:
|
||||
return outputchachesize;
|
||||
case SocketOptions.SO_BINDADDR:
|
||||
return bindaddr;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -262,7 +305,6 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
}
|
||||
connecting = false;
|
||||
if (succeed) {
|
||||
|
||||
} else if (refused) {
|
||||
throw new ConnectException("connect refused");
|
||||
} else {
|
||||
@@ -329,8 +371,8 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
this.acceptedSocketCloseListener = lsr;
|
||||
}
|
||||
|
||||
private KVSIInputStream vin;
|
||||
private KVSIOutputStream vout;
|
||||
private InputStream vin;
|
||||
private OutputStream vout;
|
||||
|
||||
private class KVSIInputStream extends InputStream {
|
||||
private DATATPacket dtp = null;
|
||||
@@ -339,9 +381,7 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
private boolean shutdown=false;
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if(shutdown)
|
||||
return -1;
|
||||
if (dtp == null || (count >= dtp.getData().length && dtp.getData().length != 0)) {
|
||||
if (dtp == null ) {
|
||||
count = 0;
|
||||
while (true) {
|
||||
if (isClosed())
|
||||
@@ -356,16 +396,24 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
synchronized (sendDeque) {
|
||||
sendDeque.wait(100);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dtp.getData().length == 0) {
|
||||
if (dtp.getSize() == 0) {
|
||||
return -1;
|
||||
} else
|
||||
return dtp.getData()[count++] & 0xff;
|
||||
} else {
|
||||
int ret= dtp.getData()[count++] & 0xff;
|
||||
if(count==dtp.getSize()) {
|
||||
DATATPacket.arrayRecycle.recycle(dtp.getData());
|
||||
dtp=null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -379,21 +427,78 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
}
|
||||
|
||||
len = Math.min(len, available());
|
||||
|
||||
int c = read();
|
||||
if (c == -1) {
|
||||
return -1;
|
||||
|
||||
|
||||
if (dtp == null ) {
|
||||
count = 0;
|
||||
while (true) {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
DATATPacket dtp2 = sendDeque.poll();
|
||||
if (dtp2 != null) {
|
||||
dtp = dtp2;
|
||||
if(countInputBytes() < inputchachesize) {
|
||||
controller.sendPacketToAddress((Inet6Address) address, new ACKTPacket(dtp.getDport(), dtp.getSport(), dtp2.getNumber(),
|
||||
true), 32768);
|
||||
}
|
||||
break;
|
||||
}
|
||||
try {
|
||||
synchronized (sendDeque) {
|
||||
sendDeque.wait(100);
|
||||
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dtp.getSize() == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
b[off]= dtp.getData()[count++] ;
|
||||
if(count==dtp.getSize()) {
|
||||
DATATPacket.arrayRecycle.recycle(dtp.getData());
|
||||
dtp=null;
|
||||
}
|
||||
}
|
||||
b[off] = (byte) c;
|
||||
|
||||
int i = 1;
|
||||
try {
|
||||
for (; i < len; i++) {
|
||||
c = read();
|
||||
if (c == -1) {
|
||||
break;
|
||||
|
||||
if (dtp == null ) {
|
||||
count = 0;
|
||||
while (true) {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
DATATPacket dtp2 = sendDeque.poll();
|
||||
if (dtp2 != null) {
|
||||
dtp = dtp2;
|
||||
if(countInputBytes() < inputchachesize) {
|
||||
controller.sendPacketToAddress((Inet6Address) address, new ACKTPacket(dtp.getDport(), dtp.getSport(), dtp2.getNumber(),
|
||||
true), 32768);
|
||||
}
|
||||
break;
|
||||
}
|
||||
try {
|
||||
synchronized (sendDeque) {
|
||||
sendDeque.wait(100);
|
||||
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dtp.getSize() == 0) {
|
||||
break;
|
||||
} else {
|
||||
b[off + i]= dtp.getData()[count++] ;
|
||||
if(count==dtp.getSize()) {
|
||||
DATATPacket.arrayRecycle.recycle(dtp.getData());
|
||||
dtp=null;
|
||||
}
|
||||
}
|
||||
b[off + i] = (byte) c;
|
||||
}
|
||||
} catch (IOException ee) {
|
||||
}
|
||||
@@ -402,40 +507,92 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
shutdown=true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
AtomicInteger i = new AtomicInteger(0);
|
||||
sendDeque.forEach((V) -> {
|
||||
i.addAndGet(V.getData().length);
|
||||
i.addAndGet(V.getSize());
|
||||
});
|
||||
if (dtp != null)
|
||||
i.addAndGet(dtp.getData().length - count);
|
||||
i.addAndGet(dtp.getSize() - count);
|
||||
return i.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private long outputcount = 0;
|
||||
private volatile long outputcount = 0;
|
||||
|
||||
private static final int LIMIT=65535;
|
||||
private class KVSIOutputStream extends OutputStream {
|
||||
|
||||
private byte[] cache=new byte[65535];
|
||||
private byte[] cache=DATATPacket.arrayRecycle.create();
|
||||
private int count=0;
|
||||
private Object lock=new Object();
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
synchronized (lock) {
|
||||
|
||||
cache[count++]=(byte) b;
|
||||
if (count >=5773 ) {//1429?
|
||||
if (count >= LIMIT) {//1429?5773?8669
|
||||
flush0();
|
||||
}else {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
int ol=off+len;
|
||||
synchronized (lock) {
|
||||
for (int i = off; i < ol; i++) {
|
||||
cache[count++]=b[i];
|
||||
if (count >= LIMIT) {//1429?5773?8669
|
||||
flush0();
|
||||
}
|
||||
}
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
private volatile TimerTask tt;
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
if(nodelay) {
|
||||
synchronized (lock) {
|
||||
flush0();
|
||||
}
|
||||
}else {
|
||||
if(tt==null) {
|
||||
tt=new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if(isClosed())
|
||||
cancel();
|
||||
try {
|
||||
synchronized (lock) {
|
||||
flush0();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
new Timer("粘包计时线程").scheduleAtFixedRate(tt, 0, delaytime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void flush0() throws IOException {
|
||||
if (count > 0) {
|
||||
try {
|
||||
while (!avaliable) {
|
||||
@@ -446,20 +603,18 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
}
|
||||
try {
|
||||
while(countOutputBytes()>outputchachesize) {
|
||||
Thread.sleep(1);
|
||||
synchronized (sendlist) {
|
||||
sendlist.wait(10);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// TODO 自动生成的 catch 块
|
||||
e.printStackTrace();
|
||||
}
|
||||
byte[]ba;
|
||||
if(count==cache.length) {
|
||||
ba=cache;
|
||||
cache=new byte[cache.length];
|
||||
}else {
|
||||
ba=Arrays.copyOf(cache, count);
|
||||
}
|
||||
SendTask x=new SendTask(controller, (Inet6Address) address, new DATATPacket(localport, port, outputcount++, ba), 5,10);
|
||||
byte[] ba=cache;
|
||||
cache=DATATPacket.arrayRecycle.create();
|
||||
|
||||
SendTask x=new SendTask(controller, (Inet6Address) address, new DATATPacket(localport, port, outputcount++, ba,count), 5,20);
|
||||
x.run();
|
||||
sendlist.add(x);
|
||||
/*controller.sendPacketToAddress((Inet6Address) address,
|
||||
@@ -470,28 +625,36 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
flush();
|
||||
SendTask x=new SendTask(controller, (Inet6Address) address, new DATATPacket(localport, port, outputcount++, new byte[0]), 5,10);
|
||||
flush0();
|
||||
SendTask x=new SendTask(controller, (Inet6Address) address, new DATATPacket(localport, port, outputcount++, DATATPacket.arrayRecycle.create(),0), 5,20);
|
||||
x.run();
|
||||
sendlist.add(x);
|
||||
/*controller.sendPacketToAddress((Inet6Address) address,
|
||||
new DATATPacket(localport, port, outputcount++, new byte[0]), 5);*/
|
||||
tt.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InputStream getInputStream() throws IOException {
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (vin == null) {
|
||||
vin = new KVSIInputStream();
|
||||
int val= vin.read();
|
||||
if(val==1) {
|
||||
vin=new InflaterInputStream(vin,new Inflater(true),LIMIT);
|
||||
}
|
||||
}
|
||||
return vin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OutputStream getOutputStream() throws IOException {
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
if (vout == null) {
|
||||
vout = new KVSIOutputStream();
|
||||
vout.write(1);
|
||||
vout.flush();
|
||||
vout=new DeflaterOutputStream(vout, new Deflater(Deflater.BEST_COMPRESSION, true), LIMIT, true);
|
||||
}
|
||||
return vout;
|
||||
}
|
||||
@@ -521,17 +684,23 @@ public class KLALBVirtualSocketImpl extends SocketImpl {
|
||||
protected void close() throws IOException {
|
||||
if (!isListening() && !isClosed()) {
|
||||
closed = true;
|
||||
try {
|
||||
|
||||
controller.sendPacketToAddress((Inet6Address) super.address, new RSTPacket(super.localport, super.port),
|
||||
65537);
|
||||
65537,2);
|
||||
} catch (NoRouteToHostException e) {
|
||||
}
|
||||
if (acceptedSocketCloseListener != null)
|
||||
acceptedSocketCloseListener.accept(this);
|
||||
else
|
||||
controller.unbind(this);
|
||||
}
|
||||
if (acceptedSocketCloseListener != null)
|
||||
acceptedSocketCloseListener.accept(this);
|
||||
else
|
||||
controller.unbind(this);
|
||||
sendCheckTask.cancel();
|
||||
|
||||
//new Exception().printStackTrace();
|
||||
}
|
||||
|
||||
private boolean closed;
|
||||
private volatile boolean closed;
|
||||
|
||||
private boolean isClosed() {
|
||||
return closed;
|
||||
|
||||
Reference in New Issue
Block a user