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 ReceivePacketSlidingWindowrecvMap=new ReceivePacketSlidingWindow(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{ 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 + "]"; } }