This commit is contained in:
2026-07-07 00:26:38 +08:00
parent 74e4360d71
commit ba61d3b5ae
28 changed files with 2411 additions and 0 deletions
@@ -0,0 +1,302 @@
package org.kne.cloud.network.kltp;
import java.io.IOException;
import java.io.InputStream;
import java.net.BindException;
import java.net.SocketTimeoutException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.kne.cloud.network.NetworkPacket;
import org.kne.cloud.network.congestion.MpscMessageBatcher;
import org.kne.cloud.network.congestion.ReceivePacketSlidingWindow;
import org.kne.cloud.network.ipv6.IPv6Address;
import org.kne.cloud.network.ipv6.IPv6Packet;
import org.kne.cloud.network.klalb.DATATPacket;
import org.kne.cloud.network.klalb.KLALBController;
public class KLTPInputStream extends InputStream implements KLTPPacketConsumer, ReadableByteChannel{
private KLALBController controller;
private IPv6Address remoteaddr;
private UUID streamUUID;
private ReceivePacketSlidingWindow<Long, KLTPPacket>recvMap=new ReceivePacketSlidingWindow<Long, KLTPPacket>(Integer.MAX_VALUE,-20);
private AtomicLong inputcount = new AtomicLong();
private KLTPPacket dataPack = null;
private long soTimeout=0;
public IPv6Address getRemoteAddress() {
return remoteaddr;
}
public KLTPInputStream(KLALBController controller,IPv6Address remoteaddr,UUID uuid) throws BindException {
this.controller=controller;
this.streamUUID =uuid;
this.remoteaddr=remoteaddr;
controller.getKLTPregister().registerReceiveStream(this);
}
@Override
public int read() throws IOException {
if (dataPack == null ||(!dataPack.getKLTPData().hasRemaining())) {
dataPack=nextPacket(true);
}
if (dataPack.getDataSize() == 0) {
return -1;
} else {
int ret= dataPack.getKLTPData().get() & 0xff;
return ret;
}
}
private KLTPPacket nextPacket(boolean block) throws IOException {
try {
KLTPPacket dtp2 =null;
if(block) {
if(soTimeout==0) {
dtp2= recvMap.take(inputcount.get());
}else {
dtp2= recvMap.take(inputcount.get(),soTimeout);
}
}else {
dtp2=recvMap.poll(inputcount.get());
}
if (dtp2 != null) {
inputcount.setPlain( inputcount.getPlain()+1);
int size=dtp2.getDataSize();
//socketMonitor.getDownloadBandwidth().recordPacket(pid, size);
//controller.getDatatMonitor().getDownloadBandwidth().recordPacket(KLALBUtils.createGlobalUUID(), size);
//checkFlowControl(dtp2);
// System.out.println("序列号:"+dtp2.getSequence());
return dtp2;
}
}catch(SocketTimeoutException e) {
close0();
throw e;
}
return null;
}
/*@Override
public int read(ByteBuffer dst) throws IOException {
int oldlmt=dst.limit();
try {
if (dataPack == null ||(!dataPack.getKLTPData().hasRemaining())) {
nextPacket();
}
if (dataPack.getDataSize() == 0) {
return -1;
} else {
int len = Math.min(dst.remaining(), available());
dst.limit(dst.position()+len);
dst.put( dataPack.getKLTPData().get()) ;
}
int i = 1;
try {
while (dst.hasRemaining()) {
if (dataPack == null ||(!dataPack.getKLTPData().hasRemaining())) {
nextPacket();
}
if (dataPack.getDataSize() == 0) {
break;
}
int min=Math.min(dataPack.getKLTPData().remaining(), dst.remaining());
int oldlm=dataPack.getKLTPData().limit();
dataPack.getKLTPData().limit(dataPack.getKLTPData().position()+min);
System.out.println("dst:"+dst+" datapack:"+dataPack);
dst.put(dataPack.getKLTPData());
dataPack.getKLTPData().limit(oldlm);
i+=min;
}
} catch (IOException ee) {
}
return i;
}catch(BufferOverflowException e) {
System.err.println("dst:"+dst+" datapack:"+dataPack);
throw e;
}finally {
dst.limit(oldlmt);
}
}*/
@Override
public int read(ByteBuffer dst) throws IOException {
if (!dst.hasRemaining()) {
return 0;
}
int totalRead = 0;
try {
// 如果当前没有数据包或当前数据包已读完,获取下一个
if (dataPack == null || (!dataPack.getKLTPData().hasRemaining()&&(dataPack.getDataSize()!=0))) {
dataPack=nextPacket(true);
}
// EOF 检查
if (dataPack.getDataSize() == 0) {
//System.out.println("EOF recv:"+dataPack);
return -1;
}
// 循环读取直到 dst 满或没有更多数据
while (dst.hasRemaining()) {
// 获取当前数据包的剩余数据
ByteBuffer src = dataPack.getKLTPData();
if (!src.hasRemaining()) {
// 当前包读完,尝试获取下一个包
dataPack=nextPacket(false);
if (dataPack==null||dataPack.getDataSize() == 0) {
break; // 下一个包还没来或EOF
}
src = dataPack.getKLTPData();
}
// 计算本次可拷贝的字节数
int bytesToCopy = Math.min(src.remaining(), dst.remaining());
// 保存原 limit
int srcOldLimit = src.limit();
int dstOldLimit = dst.limit();
try {
// 设置临时 limit
src.limit(src.position() + bytesToCopy);
dst.limit(dst.position() + bytesToCopy);
// 执行拷贝
dst.put(src);
totalRead += bytesToCopy;
} finally {
// 恢复 limit
src.limit(srcOldLimit);
dst.limit(dstOldLimit);
}
}
} catch (SocketTimeoutException e) {
close0();
throw e;
} catch (BufferOverflowException e) {
// 不应该发生,因为我们做了 min() 检查
throw new IOException("Buffer overflow in KLTPInputStream.read", e);
}
return totalRead > 0 ? totalRead : -1;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return read(ByteBuffer.wrap(b,off,len));
}
@Override
public void close() throws IOException {
close0();
}
private void close0() throws IOException{
try {
recvMap.close();
}finally {
controller.getKLTPregister().unregisterReceiveStream(this);
}
}
@Override
public int available() throws IOException {
//long i = recvMap.getRecvWindowUsed();
long i=0;
if (dataPack != null)
i+=dataPack.getKLTPData().remaining();
return (int) i;
}
@Override
public boolean isOpen() {
return !recvMap.isClosed();
}
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
long lth=0;
for(int i=offset;i<offset+length;i++) {
lth+=read(dsts[i]);
if(dsts[i].hasRemaining()) {
break;
}
}
return lth;
}
@Override
public void accept(IPv6Packet u) {
if(u.getPayload() instanceof KLTPPacket) {
KLTPPacket kltp=(KLTPPacket) u.getPayload();
switch(kltp.getType()) {
case KLTPPacket.KLTP_TYPE_DATA:
//ackSequenceBatcher.putMessage(kseq);
recvMap.put(kltp.getSequence(), kltp);
controller.getIpv6Router().runPacketSendTask(()->{
KLTPPacket pack=new KLTPPacket(streamUUID,KLTPPacket.KLTP_TYPE_ACK,kltp.getSequence(),0);
pack.setCE(u.isCE());
return controller.createPacketToAddress(remoteaddr,0,pack);
});
break;
case KLTPPacket.KLTP_TYPE_DATAFIN:
//ackSequenceBatcher.putMessage(kseq2);
recvMap.put(kltp.getSequence(), kltp);
controller.getIpv6Router().runPacketSendTask(()->{
KLTPPacket pack=new KLTPPacket(streamUUID,KLTPPacket.KLTP_TYPE_ACK,kltp.getSequence(),0);
pack.setCE(u.isCE());
return controller.createPacketToAddress(remoteaddr,0,pack);
});
//System.out.println(inputcount+" "+ recvMap.getRecvMap());
break;
}
}
}
@Override
public UUID getStreamUUID() {
return streamUUID;
}
public boolean isClosed() {
return recvMap.isClosed();
}
public void setSoTimeout(int value) {
soTimeout=value*1000000L;
}
public int getSoTimeout() {
return (int) (soTimeout/1000000L);
}
@Override
public String toString() {
return "KLTPInputStream [streamUUID=" + streamUUID + ", recvMap=" + recvMap + "]";
}
}
@@ -0,0 +1,375 @@
package org.kne.cloud.network.kltp;
import java.io.IOException;
import java.io.OutputStream;
import java.net.BindException;
import java.net.Inet6Address;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import org.kne.concurrent.*;
import org.kne.cloud.network.NetworkPacket;
import org.kne.cloud.network.congestion.CongestionAlgorithm;
import org.kne.cloud.network.congestion.DCTCP2CongestionAlgorithm;
import org.kne.cloud.network.congestion.DCTCPCongestionAlgorithm;
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
import org.kne.cloud.network.ipv6.IPv6Address;
import org.kne.cloud.network.ipv6.IPv6Packet;
import org.kne.cloud.network.klalb.DATATPacket;
import org.kne.cloud.network.klalb.KLALBController;
import java.util.UUID;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.*;
public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer,WritableByteChannel{
private static final int HEADER_CALIBRATE = 150;
private KLALBController controller;
private IPv6Address remoteaddr;
public IPv6Address getRemoteAddress() {
return remoteaddr;
}
public KLTPOutputStream(KLALBController controller,IPv6Address remoteaddr,UUID uuid) throws BindException {
this.controller=controller;
this.streamUUID =uuid;
this.remoteaddr=remoteaddr;
if(controller.getConfigItem()!=null)
this.delaytime=controller.getConfigItem().getNagleDelayTime();
algorithm.setWindowControlConsumer((window)->{
sendMap.setWindowSize(window);
});
controller.getKLTPregister().registerSendStream(this);
}
private UUID streamUUID;
private int MTU=8192;
private CongestionAlgorithm algorithm=new DCTCPCongestionAlgorithm();
private SendPacketSlidingWindow<Long,KLTPPacket>sendMap=new SendPacketSlidingWindow<>(algorithm, 4*MTU,HEADER_CALIBRATE,false);
{
sendMap.setResendConsumer((dtp)->{
if(dtp.getSendCounter()>=50) {
System.err.println("send error!");
try {
close0(false);
} catch (IOException e) {
e.printStackTrace();
}
return;
}
controller.getIpv6Router().runPacketSendTask(()->{
long length= dtp.getTotalLength();
//socketRawMonitor.getUploadBandwidth().recordPacket(pidg.generate(), (int) length);
//System.out.println("第"+(dtp.getSendCounter()-1)+"次重传:"+dtp);
return controller.createPacketToAddress( remoteaddr,0,dtp,1);
});
dtp.incSendCounter();
});
}
private AtomicLong outputcount=new AtomicLong( 0);
private KLTPPacket dataPack =null;
private long delaytime=2;
private Lock olock=new SpinLock();
private volatile boolean autoFlush=true;
@Override
public void write(int b) throws IOException {
if (sendMap.isClosed())
throw new SocketException("Socket is closed");
if(olock!=null)
olock.lock();
createDataPack();
try {
dataPack.getKLTPData().put((byte) b);
if (dataPack!=null&& dataPack.getKLTPData().hasRemaining()) {
if(autoFlush)
delayFlush();
}else {
flush0();
}
}finally {
if(olock!=null)
olock.unlock();
}
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
write(ByteBuffer.wrap(b, off, len));
return ;
}
private int writeWithoutFlush(ByteBuffer src)throws IOException {
if (sendMap.isClosed())
throw new SocketException("Socket is closed");
int counter=0;
if(olock!=null)
olock.lock();
try {
while(src.hasRemaining()) {
createDataPack();
int min=Math.min(src.remaining(), dataPack.getKLTPData().remaining());
int olm=src.limit();
src.limit(src.position()+min);
dataPack.getKLTPData().put(src);
counter+=min;
src.limit(olm);
if (!dataPack.getKLTPData().hasRemaining()) {
flush0();
}
}
}finally {
if(olock!=null)
olock.unlock();
}
return counter;
}
@Override
public int write(ByteBuffer src) throws IOException {
if (sendMap.isClosed())
throw new SocketException("Socket is closed");
int counter=0;
if(olock!=null)
olock.lock();
try {
while(src.hasRemaining()) {
createDataPack();
int min=Math.min(src.remaining(), dataPack.getKLTPData().remaining());
int olm=src.limit();
src.limit(src.position()+min);
dataPack.getKLTPData().put(src);
counter+=min;
src.limit(olm);
if (!dataPack.getKLTPData().hasRemaining()) {
flush0();
}
}
if(dataPack!=null&& dataPack.getKLTPData().position()>0) {
if(autoFlush)
delayFlush();
}
}finally {
if(olock!=null)
olock.unlock();
}
return counter;
}
private void createDataPack() {
if(dataPack==null) {
long pl=outputcount.getPlain();
dataPack=new KLTPPacket(streamUUID,KLTPPacket.KLTP_TYPE_DATA,pl++, MTU);
outputcount.setPlain(pl);
//System.out.println("EOF:"+dataPack);
}
}
public void waitForAllAcknowledged(int timeout) throws IOException {
long start=System.nanoTime();
while(true){
if (sendMap.isClosed())
throw new SocketException("Socket is closed");
if(sendMap.isEmpty())
break;
if(timeout!=0&&(System.nanoTime()-start>timeout*1000000L))
throw new SocketTimeoutException("wait for acknowledged timout");
}
}
AtomicReference<IOException> ioe=new AtomicReference<>();
private volatile ScheduledFuture tt;
@Override
public void flush() throws IOException {
if(olock!=null)
olock.lock();
try {
delayFlush();
}finally {
if(olock!=null)
olock.unlock();
}
}
public void forceFlush() throws IOException{
if(olock!=null)
olock.lock();
try {
flush0();
}finally {
if(olock!=null)
olock.unlock();
}
}
public void delayFlush()throws IOException{
if(delaytime<=0) {
flush0();
}else {
if(tt==null) {
Runnable r= new Runnable() {
@Override
public void run() {
if(sendMap.isClosed())
tt.cancel(false);
try {
if(olock!=null)
olock.lock();
try {
flush0();
}finally {
if(olock!=null)
olock.unlock();
}
} catch (IOException e) {
ioe.set(e);
}
}
};
tt=controller.getScheduleTimer().scheduleAtFixedRate (r, delaytime, delaytime,TimeUnit.NANOSECONDS);
}
IOException ioex=ioe.get();
if(ioex!=null) {
ioex.fillInStackTrace();
throw ioex;
}
}
}
private void flush0() throws IOException {
KLTPPacket pack=dataPack;
if (pack!=null&&pack.getKLTPData().position() > 0) {
sendMap.waitForAvaliable();
controller.getIpv6Router().runPacketSendTask(()->{
pack.getKLTPData().flip();
pack.incSendCounter();
sendMap.put(pack.getSequence(),pack);
int size= pack.getKLTPData().limit();
//socketMonitor.getUploadBandwidth().recordPacket(pid, size);
//controller.getDatatMonitor().getUploadBandwidth().recordPacket(KLALBUtils.createGlobalUUID(), size);
//socketRawMonitor.getUploadBandwidth().recordPacket(pid, size);
return controller.createPacketToAddress(remoteaddr,0,pack);
});
dataPack=null;
}
}
@Override
public void close() throws IOException {
close0(true);
}
private void close0(boolean grace) throws IOException {
try {
if(sendMap.isClosed())
return;
if(grace) {
if(olock!=null)
olock.lock();
try {
flush0();
}finally {
if(olock!=null)
olock.unlock();
}
long pl=outputcount.getPlain();
KLTPPacket pack=new KLTPPacket(streamUUID,KLTPPacket.KLTP_TYPE_DATAFIN, pl++ ,MTU);
outputcount.setPlain(pl);
pack.getKLTPData(). flip();
pack.incSendCounter();
controller.getIpv6Router().runPacketSendTask (()->{
return controller.createPacketToAddress(remoteaddr,0,pack);
});
sendMap.put(pack.getSequence(),pack);
// System.out.println("EOF send:"+pack);
}
sendMap.close();
}finally {
if(tt!=null)
tt.cancel(false);
controller.getKLTPregister().unregisterSendStream(this);
}
}
@Override
public boolean isOpen() {
return !sendMap.isClosed();
}
public boolean isAutoFlush() {
return autoFlush;
}
public void setAutoFlush(boolean b) {
autoFlush=b;
}
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
long lth=0;
for(int i=offset;i<offset+length;i++) {
lth+=writeWithoutFlush(srcs[i]);
}
if(dataPack!=null&& dataPack.getKLTPData().position()>0) {
if(autoFlush)
flush();
}
return lth;
}
@Override
public void accept(IPv6Packet u) {
if(u.getPayload() instanceof KLTPPacket) {
KLTPPacket kltp=(KLTPPacket) u.getPayload();
switch(kltp.getType()) {
case KLTPPacket.KLTP_TYPE_ACK:
sendMap.ack(kltp.getSequence(), kltp.isCE());
break;
}
}
}
@Override
public UUID getStreamUUID() {
return streamUUID;
}
public boolean isClosed() {
return sendMap.isClosed();
}
@Override
public String toString() {
return "KLTPOutputStream [streamUUID=" + streamUUID + ", sendMap=" + sendMap + "]";
}
}
@@ -0,0 +1,186 @@
package org.kne.cloud.network.kltp;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import org.kne.cloud.network.NetworkPacket;
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6Payload;
import org.kne.io.KNEChannels;
public class KLTPPacket extends IPv6Payload {
public static final int KLTP_PROTOCOL_NUMBER=253;
public static final int KLTP_HEADER_LENGTH=24+8;
public static final int KLTP_TYPE_DATA=0;
public static final int KLTP_TYPE_DATAFIN=1;
public static final int KLTP_TYPE_ACK=2;
protected ByteBuffer kltpHeader;
protected ByteBuffer kltpData;
public KLTPPacket() {
super(KLTP_PROTOCOL_NUMBER);
kltpHeader=NetworkPacket.bufferAllocator.allocate(KLTP_HEADER_LENGTH);
}
public KLTPPacket(UUID uuid,int type,long seq,int mtulimit) {
super(KLTP_PROTOCOL_NUMBER);
kltpHeader=NetworkPacket.bufferAllocator.allocate(KLTP_HEADER_LENGTH);
setUUID(uuid);
setType(type);
setSequence(seq);
kltpData=NetworkPacket.bufferAllocator.allocate(mtulimit);
}
public UUID getUUID() {
long h=kltpHeader.getLong(0);
long l=kltpHeader.getLong(8);
return new UUID(h,l);
}
public void setUUID(UUID uuid) {
kltpHeader.putLong(0, uuid.getMostSignificantBits());
kltpHeader.putLong(8, uuid.getLeastSignificantBits());
}
public int getPayloadLength() {
return kltpHeader.getInt(16);
}
public void setPayloadLength(int payloadLength) {
kltpHeader.putInt(16,payloadLength);
}
public int getChecksum() {
return kltpHeader.getChar(20);
}
public void setChecksum(int checksum) {
kltpHeader.putChar(20, (char) checksum);
}
public int getType() {
return kltpHeader.get(22);
}
public void setType(int type) {
kltpHeader.put(22, (byte) type);
}
public boolean isCE() {
int v=kltpHeader.get(23)&1;
return v!=0;
}
public void setCE(boolean b) {
kltpHeader.put(23, (byte) (b?1:0));
}
public long getSequence() {
return kltpHeader.getLong(24);
}
public void setSequence(long kseq) {
kltpHeader.putLong(24,kseq);
}
@Override
public long getTotalLength() {
return KLTP_HEADER_LENGTH+kltpData.limit();
}
@Override
public void writeToChannel(WritableByteChannel dto) throws IOException {
setPayloadLength(kltpData.limit());
dto.write(kltpHeader.slice(0, KLTP_HEADER_LENGTH));
dto.write(kltpData.slice(0, kltpData.limit()));
}
@Override
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
kltpHeader.clear();
KNEChannels.readFully(din ,kltpHeader);
kltpHeader.flip();
kltpData=NetworkPacket.bufferAllocator.allocate(getPayloadLength());
KNEChannels.readFully(din, kltpData);
kltpData.flip();
}
public static IPv6Payload readKLTPPacketFromChannel(ReadableByteChannel din) throws IOException {
KLTPPacket pack=new KLTPPacket();
pack.readFromChannel(din);
return pack;
}
private int sendCounter=0;
public int getSendCounter() {
return sendCounter;
}
public void incSendCounter() {
sendCounter++;
}
public int getDataSize() {
return kltpData.limit();
}
public String toString() {
StringBuilder sb=new StringBuilder();
switch(getType()) {
case KLTP_TYPE_DATA:
sb.append("DATA ");
sb.append(getUUID());
sb.append(' ');
sb.append(getSequence());
sb.append(' ');
sb.append(getKLTPData());
break;
case KLTP_TYPE_DATAFIN:
sb.append("DATAFIN ");
sb.append(getUUID());
sb.append(' ');
sb.append(getSequence());
sb.append(' ');
sb.append(getKLTPData());
break;
case KLTP_TYPE_ACK:
sb.append("ACK ");
sb.append(getUUID());
sb.append(' ');
sb.append(getSequence());
break;
default:
sb.append("UNKNOWN ");
sb.append(getUUID());
break;
}
return sb.toString();
}
public ByteBuffer getKLTPData() {
return kltpData;
}
}
@@ -0,0 +1,10 @@
package org.kne.cloud.network.kltp;
import java.util.UUID;
import org.kne.cloud.network.srv6.IPv6PacketConsumer;
public interface KLTPPacketConsumer extends IPv6PacketConsumer {
public UUID getStreamUUID();
}
@@ -0,0 +1,108 @@
package org.kne.cloud.network.kltp;
import java.io.IOException;
import java.net.BindException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.kne.cloud.network.ipv6.IPv6Address;
import org.kne.cloud.network.ipv6.IPv6Packet;
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6Payload;
import org.kne.cloud.network.ipv6.IPv6ProtocolRegister;
import org.kne.cloud.network.klalb.BindableConsumer;
import org.kne.cloud.network.klalb.KLALBController;
import org.kne.cloud.network.klalb.PortBinder;
import org.kne.cloud.network.srv6.IPv6PacketConsumer;
public class KLTPProtocolRegister extends PortBinder<KLTPSessionPacket> implements IPv6ProtocolRegister {
private KLALBController controller;
public KLTPProtocolRegister(KLALBController controller) {
super(controller.getSelf().getAddress());
this.controller = controller;
}
private static final boolean showpacket=false;
private static final boolean debug=false;
private ConcurrentHashMap<UUID, KLTPPacketConsumer> recvRegisterMap=new ConcurrentHashMap<UUID, KLTPPacketConsumer>();
private ConcurrentHashMap<UUID, KLTPPacketConsumer> sendRegisterMap=new ConcurrentHashMap<UUID, KLTPPacketConsumer>();
public void registerReceiveStream(KLTPPacketConsumer kltp) throws BindException {
if(recvRegisterMap.putIfAbsent(kltp.getStreamUUID(), kltp)!=null) {
throw new BindException("KLTP receive UUID "+kltp.getStreamUUID()+" already used!");
}else {
if(debug)
System.out.println("接收流打开:"+kltp.getStreamUUID());
}
}
public void unregisterReceiveStream(KLTPPacketConsumer kltp) {
recvRegisterMap.remove(kltp.getStreamUUID(), kltp);
if(debug)
System.out.println("接收流关闭:"+kltp.getStreamUUID());
}
public void registerSendStream(KLTPPacketConsumer kltp) throws BindException {
if(sendRegisterMap.putIfAbsent(kltp.getStreamUUID(), kltp)!=null) {
throw new BindException("KLTP send UUID "+kltp.getStreamUUID()+" already used!");
}else {
if(debug)
System.out.println("发送流打开:"+kltp.getStreamUUID());
}
}
public void unregisterSendStream(KLTPPacketConsumer kltp) {
sendRegisterMap.remove(kltp.getStreamUUID(), kltp);
if(debug)
System.out.println("发送流关闭:"+kltp.getStreamUUID());
}
@Override
public boolean onaccept(IPv6Packet packx) throws IOException {
IPv6Payload pl = packx.getPayload();
if (pl instanceof KLTPPacket) {
KLTPPacket kltp = (KLTPPacket) pl;
if (showpacket)
System.out.println("KLTP_RX:" + kltp);
if(kltp.getType() ==KLTPPacket.KLTP_TYPE_ACK) {
KLTPPacketConsumer cosu= sendRegisterMap.get(kltp.getUUID());
if(cosu!=null) {
cosu.accept(packx);
return true;
}
}else {
KLTPPacketConsumer cosu= recvRegisterMap.get(kltp.getUUID());
if(cosu!=null) {
cosu.accept(packx);
return true;
}else {
if(kltp.getSequence()==0) {
IPv6Address srca=packx.getSourceAddress();
KLTPInputStream kins=new KLTPInputStream(controller, srca, kltp.getUUID());
kins.accept(packx);
KLTPSessionPacket sess=new KLTPSessionPacket(kins);
sess.readFromChannel(kins);
BindableConsumer<KLTPSessionPacket> con;
if((con=distributePacketToConsumer(srca, sess))!=null) {
//System.out.println(this);
con.accept(sess);
System.out.println("接受连接:"+sess);
return true;
}else {
kins.close();
System.out.println("丢弃连接:"+sess);
}
}else {
//System.out.println("丢弃连接:"+kltp);
}
}
}
}
return false;
}
}
@@ -0,0 +1,105 @@
package org.kne.cloud.network.kltp;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import org.kne.cloud.network.ByteBufferAllocator;
import org.kne.cloud.network.NetworkPacket;
import org.kne.cloud.network.klalb.PortPacket;
import org.kne.io.KNEChannels;
public class KLTPSessionPacket extends NetworkPacket implements PortPacket{
private static final int KLTP_SESSION_HEADER_LENGTH=8;
private ByteBuffer header=NetworkPacket.bufferAllocator.allocate(KLTP_SESSION_HEADER_LENGTH);
private KLTPInputStream inputstream;
public KLTPSessionPacket(int sport, int dport,KLTPInputStream inputstream) {
setSrcPort(sport);
setDstPort(dport);
this.inputstream=inputstream;
}
public KLTPSessionPacket(int sport, int dport) {
setSrcPort(sport);
setDstPort(dport);
}
public KLTPSessionPacket() {
}
public KLTPSessionPacket(KLTPInputStream inputstream) {
super();
this.inputstream = inputstream;
}
public KLTPInputStream getInputstream() {
return inputstream;
}
@Override
public long getTotalLength() {
return KLTP_SESSION_HEADER_LENGTH;
}
@Override
public void writeToChannel(WritableByteChannel dto) throws IOException {
dto.write(header.slice(0, KLTP_SESSION_HEADER_LENGTH));
//System.out.println("writesession:"+header);
}
@Override
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
header.limit(KLTP_SESSION_HEADER_LENGTH);
KNEChannels.readFully(din, header);
header.flip();
//System.out.println("readsesion:"+header);
}
@Override
public int hashCode() {
return getSrcPort()^getDstPort();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
KLTPSessionPacket other = (KLTPSessionPacket) obj;
return (getSrcPort()==other.getSrcPort())&&(getDstPort()==other.getDstPort());
}
@Override
protected boolean needEndPosition() {
return false;
}
public void setSrcPort(int sport) {
header.putInt(0,sport);
}
public void setDstPort(int dport) {
header.putInt(4,dport);
}
@Override
public int getSrcPort() {
return header.getInt(0);
}
@Override
public int getDstPort() {
return header.getInt(4);
}
@Override
public String toString() {
return "KLTPSession "+getSrcPort()+"->"+getDstPort();
}
}