OSDN Git Service

*** empty log message ***
authorSenju Higurashi <senju@users.sourceforge.jp>
Sat, 7 Jan 2006 16:02:06 +0000 (16:02 +0000)
committerSenju Higurashi <senju@users.sourceforge.jp>
Sat, 7 Jan 2006 16:02:06 +0000 (16:02 +0000)
.cvsignore [new file with mode: 0644]
src/net/excentrics/bandWidth/.cvsignore [new file with mode: 0644]
src/net/excentrics/bandWidth/AsymmetricalCallException.java [new file with mode: 0644]
src/net/excentrics/bandWidth/BandWidthController.java [new file with mode: 0644]
src/net/excentrics/bandWidth/SizeAndInterval.java [new file with mode: 0644]
src/net/excentrics/bandWidth/SocketChannelWriter.java [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..dac76d2
--- /dev/null
@@ -0,0 +1,5 @@
+.settings
+bin
+doc
+.project
+.classpath
diff --git a/src/net/excentrics/bandWidth/.cvsignore b/src/net/excentrics/bandWidth/.cvsignore
new file mode 100644 (file)
index 0000000..9daeafb
--- /dev/null
@@ -0,0 +1 @@
+test
diff --git a/src/net/excentrics/bandWidth/AsymmetricalCallException.java b/src/net/excentrics/bandWidth/AsymmetricalCallException.java
new file mode 100644 (file)
index 0000000..2214477
--- /dev/null
@@ -0,0 +1,12 @@
+package net.excentrics.bandWidth;
+
+public class AsymmetricalCallException extends Exception {
+
+
+       public AsymmetricalCallException(String message) {
+               super(message);
+               // TODO \8e©\93®\90\90¬\82³\82ê\82½\83R\83\93\83X\83g\83\89\83N\83^\81[\81E\83X\83^\83u
+       }
+
+
+}
diff --git a/src/net/excentrics/bandWidth/BandWidthController.java b/src/net/excentrics/bandWidth/BandWidthController.java
new file mode 100644 (file)
index 0000000..b300aa2
--- /dev/null
@@ -0,0 +1,204 @@
+package net.excentrics.bandWidth;
+
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * \82±\82Ì\83N\83\89\83X\82Í\83X\83\8d\83b\83g\83\8a\83\93\83O\82ð\90¬\8c÷\82³\82¹\82é\82½\82ß\93à\95\94\93I\82É\8eg\97p\82³\82ê\82é\81B
+ * 
+ * @author senju
+ * 
+ */
+class BandWidthController {
+       private final static long defaultCycle = 100; // \83f\83t\83H\83\8b\83g\82Ì\83T\83C\83N\83\8b\8e\9e\8aÔ\81B\83~\83\8a\95b\82Å\90Ý\92è\81B
+
+       private final static int defaultSpeedCount = 70;
+
+       private static final int min_cycle = 10; // \83T\83C\83N\83\8b\82ª\83I\81[\83o\81[\83\89\83C\83h\82³\82ê\82é\8dÛ\82Ì\8dÅ\8f¬\82Ì\92l
+
+       private static final int defaultAdjust = 10;
+       private double bandWidth = 0;
+
+       private int bytePerCycle = 0;
+
+       private long cycle;
+       
+       private long startTime;
+
+       private long sentSize; //startTime\8e\9e\93_\82©\82ç\8c»\8dÝ\82Ü\82Å\91\97\82ç\82ê\82½\83f\81[\83^\82Ì\97Ê\82ðbyte\82Å\8e¦\82·\81B
+       
+       private int wellSentCount; //\8ew\92è\82µ\82½\83T\83C\83Y\92Ê\82è\82Ì\83f\81[\83^\82ª\91\97\82ç\82ê\82½\89ñ\90\94\81B
+       //\88ê\93x\82Å\82à\81i\83V\83X\83e\83\80\82Ì\91\97\90M\83o\83b\83t\83@\82ª\88ì\82ê\82½\82È\82Ç\82Ì\97\9d\97R\82Å\81jpostWrite\82Ì
+       //writtenSize\82ªpreWrite\82Ì\8ew\92è\82µ\82½\92l\82Æ\88á\82Á\82Ä\82¢\82½\82ç\83J\83E\83\93\83g\82Í\83\8a\83Z\83b\83g\82³\82ê\82é\81B
+       
+       private long maySentSize; //\91O\89ñpreWrite\82ª\95Ô\82µ\82½\81u\91\97\90M\82³\82ê\82é\82×\82«\83T\83C\83Y\81v
+       
+       private long totalSpeed; // startTime\8e\9e\93_\82©\82ç\8c»\8dÝ\82Ü\82Å\82Ì\91\97\8fo\91¬\93x\82ð\95\\82·\81B(bit per second)
+
+       private int adjustmentCount = defaultAdjust;
+       
+       private LinkedList<Integer> sizeList;
+
+       private int speedCount = defaultSpeedCount; // \8c»\8dÝ\82Ì\93]\91\97\91¬\93x\82ð\92²\82×\82é\8e\9e\82É\89½\8cÂ\82ÌsizeList\93à\82Ì\97v\91f\82ð\8eg\82¤\82©\81B
+
+       private LinkedList<Long> timeList;
+
+       public BandWidthController() {
+               timeList = new LinkedList<Long>();
+               sizeList = new LinkedList<Integer>();
+               cycle = defaultCycle;
+               setBytePerCycle();
+       }
+
+       /**
+        * @return \83X\83\8d\83b\83g\83\8a\83\93\83O\82ð\90¬\8c÷\82³\82¹\82é\82½\82ß\82É\8f\91\82«\8d\9e\82Ü\82ê\82é\82×\82«\83T\83C\83Y\82ð\83o\83C\83g\82Å\95Ô\82·\81\82Ü\82½\81A\8e\9f\82Ì\8f\91\82«\8d\9e\82Ý\82Ü\82Å\82Ì\8aú\8aÔ\82ð\83~\83\8a\95b\82Å\95Ô\82·\81B
+        *         \8f\91\82«\8d\9e\82Þ\83T\83C\83Y\82É\90§\8cÀ\82ª\95K\97v\82È\82¢\8fê\8d\87\82Í-1\82ð\95Ô\82·\81B
+        */
+private SizeAndInterval calculationSizeForWrite(int bufferSize) {
+               if (bandWidth == 0)
+                       return new SizeAndInterval(-1, 0);
+               if (timeList.isEmpty())                 
+                       return new SizeAndInterval(bytePerCycle, cycle);
+       
+               double currentBps = getCurrentBps();
+               
+               
+                       System.err.println();                   
+                       System.err.println("bandwidth(bps): " + bandWidth);
+                       System.err.println("currentBps(bps): " + currentBps);
+                       System.err.println("bandwidth(Kbps): " + bandWidth / 1000);
+                       System.err.println("currentBps(Kbps): " + currentBps / 1000);
+                       System.err.println("bandwidth(Mbps): " + bandWidth / 1000 / 1000);
+                       System.err.println("currentBps(Mbps): " + currentBps / 1000 / 1000);
+                       System.err.println("wellsent: " + wellSentCount);
+                       System.err.println("totalspeed: " + totalSpeed);
+               
+               
+               // \8c»\8dÝ\82Ì\91¬\93x\82ªbandWidth\82æ\82è\8fo\82Ä\82¢\82é\8fê\8d\87\82Í\8f\91\82«\8d\9e\82Ü\82È\82¢\81B
+               if (currentBps > bandWidth)
+                       return new SizeAndInterval(0, cycle);
+
+               // \82»\82¤\82Å\82È\82­\81A\83o\83b\83t\83@\82Ì\83T\83C\83Y\82à\8f\\95ª\82È\8fê\8d\87\82Í\8f\91\82«\8d\9e\82Þ\81B
+               if (bufferSize >= bytePerCycle){
+                       if(wellSentCount >= adjustmentCount){
+                               wellSentCount = 0;
+                               /*\90\94\89ñ\82É\88ê\93x\81A\8c»\8dÝ\82Ì\91¬\93x\82¾\82¯\82Å\82È\82­\81A\83g\81[\83^\83\8b\82Ì\93]\91\97\91¬\93x\82©\82ç
+                                * \92²\90®\82ð\8ds\82¤\81B
+                                */
+                               if(totalSpeed / bandWidth < 1){ //\90§\8cÀ\91¬\93x\82Ì9\8a\84\82ð\89º\89ñ\82Á\82Ä\82¢\82½\82ç
+                                       return new SizeAndInterval(bytePerCycle,0);
+                               }
+                       }
+                       return new SizeAndInterval(bytePerCycle, cycle);
+               }
+
+               // \83o\83b\83t\83@\81[\83T\83C\83Y\82ª\91«\82è\82È\82¢\8fê\8d\87\81Acycle\82ð\83I\81[\83o\81[\83\89\83C\83h\82·\82é\81B
+               double rate = bufferSize / bytePerCycle;
+               return new SizeAndInterval(bytePerCycle, Math.max((int) (cycle * rate),min_cycle));
+       }
+
+       public double getBandWidth() {
+               return bandWidth;
+       }
+
+       private double getCurrentBps() {
+               // speedCount\8cÂ\82Ì\83T\83C\83Y\82Ì\8d\87\8cv\82ð\8b\81\82ß\81A\8c»\8dÝ\82Ì\91¬\93x\82ð\8b\81\82ß\82é\81B
+               int firstIndex = Math.max(sizeList.size() - speedCount, 0);
+               ListIterator li = sizeList.listIterator(firstIndex);
+               int sizeInByte = 0;
+               while (li.hasNext()) {
+                       Integer s = (Integer) li.next();
+                       sizeInByte += s.intValue();
+               }
+               long startTime = timeList.get(firstIndex);
+               long currentTime = System.currentTimeMillis();
+               System.err.println("real interval: "
+                               + (timeList.getLast() - currentTime));
+               long intervalInMillis = currentTime - startTime;
+               assert intervalInMillis >= 0;
+               intervalInMillis = Math.max(1, intervalInMillis);
+               double intervalInSecond = intervalInMillis / 1000.0;
+               double currentBps = sizeInByte * 8 / intervalInSecond;
+               return currentBps;
+       }
+
+       /**
+        * 
+        * @param bufferSize
+        *            \8eg\97p\82µ\82Ä\82¢\82é\83o\83b\83t\83@\82Ì\83T\83C\83Y
+        * @return \8f\91\82«\8d\9e\82Þ\82×\82«\83T\83C\83Y(byte)\81A\82¨\82æ\82Ñ\8e\9f\89ñ\8cÄ\82Ñ\8fo\82µ\82Ü\82Å\82Ì\8aÔ\8au(\83~\83\8a\95b)\82ð\95Ô\82·
+        */
+       public SizeAndInterval preWrite(int bufferSize) {
+               SizeAndInterval si = calculationSizeForWrite(bufferSize);
+               timeList.add(System.currentTimeMillis());
+               if(timeList.size() == 1){
+                       startTime = timeList.get(0);
+               }
+               // TODO: \83f\83o\83b\83O\97p
+               System.err.println(si);
+               
+               maySentSize = si.getSize();
+               return si;
+       
+       }
+
+       public long getCycle() {
+               return cycle;
+       }
+
+       /**
+        * @param writtenSize
+        *            \8eÀ\8dÛ\82É\8f\91\82«\8d\9e\82Ü\82ê\82½\83T\83C\83Y
+        * @throws AsymmetricalCallException
+        *             preWrite\82ð\8cÄ\82Ñ\8fo\82·\91O\82ÉpostWrite\82ª\8cÄ\82Î\82ê\82½\8e\9e
+        */
+       public void postWrite(int writtenSize) throws AsymmetricalCallException {
+
+               sentSize += writtenSize;
+               if(timeList.size() > 0){
+                       long elapsedTime = (timeList.getLast() - startTime )/ 1000;
+                       if(elapsedTime > 0)
+                               totalSpeed = sentSize * 8/ elapsedTime;
+               }
+               
+               if(writtenSize == maySentSize)
+                       wellSentCount++;
+               else
+                       wellSentCount = 0;
+
+               sizeList.add(writtenSize);
+               if (timeList.size() > 100) {
+                       for (int i = 0; i < 20; i++) {
+                               timeList.remove();
+                               sizeList.remove();
+                       }
+               }
+               if (sizeList.size() != timeList.size()) {
+                       throw new AsymmetricalCallException(
+                                       "preWrite and postWrite called asymmetric.");
+               }
+       }
+
+       /**
+        * @param bandWidth
+        *            \91Ñ\88æ\82ðbps(bit per second) \82Å\97^\82¦\82é\81B0\82ª\97^\82¦\82ç\82ê\82½\8fê\8d\87\91Ñ\88æ\90§\8cÀ\82ð\8ds\82í\82È\82¢\81B
+        */
+       public void setBandWidth(double bandWidth) {
+               this.bandWidth = bandWidth;
+               sizeList.clear();
+               timeList.clear();
+               setBytePerCycle();
+       }
+
+       private void setBytePerCycle() {
+               bytePerCycle = (int) (bandWidth / 1000 * cycle / 8);
+       }
+       public void setCycle(long cycle) {
+               this.cycle = cycle;
+               setBytePerCycle();
+       }
+
+       public long getTotalSpeed() {
+               return totalSpeed;
+       }
+}
diff --git a/src/net/excentrics/bandWidth/SizeAndInterval.java b/src/net/excentrics/bandWidth/SizeAndInterval.java
new file mode 100644 (file)
index 0000000..f1b33c5
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * 
+ */
+package net.excentrics.bandWidth;
+
+class SizeAndInterval {
+       private int size; //\83o\83C\83g
+       private long interval; //\83~\83\8a\95b
+       public SizeAndInterval(int size, long interval) {
+               this.setSize(size);
+               this.setInterval(interval);
+       }
+       /**
+        * @param size \90Ý\92è\82·\82é size\81B
+        */
+       public void setSize(int size) {
+               this.size = size;
+       }
+       /**
+        * @return size \82ð\96ß\82µ\82Ü\82·\81B
+        */
+       public int getSize() {
+               return size;
+       }
+       /**
+        * @param interval \90Ý\92è\82·\82é interval\81B
+        */
+       public void setInterval(long interval) {
+               this.interval = interval;
+       }
+       /**
+        * @return interval \82ð\96ß\82µ\82Ü\82·\81B
+        */
+       public long getInterval() {
+               return interval;
+       }
+       @Override
+       public String toString() {
+               return "size: " + size + " interval: "+ interval;
+       }
+}
\ No newline at end of file
diff --git a/src/net/excentrics/bandWidth/SocketChannelWriter.java b/src/net/excentrics/bandWidth/SocketChannelWriter.java
new file mode 100644 (file)
index 0000000..3e03fd3
--- /dev/null
@@ -0,0 +1,108 @@
+package net.excentrics.bandWidth;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+/**
+ * <p>java.nio.SocketChannel\82Ì\91\97\90M\91Ñ\88æ\82ð\90§\8cÀ\82·\82é\82½\82ß\82Ì\83N\83\89\83X\82Å\82·\81B
+ * <p>\91S\82Ä\82Ì\83\81\83\\83b\83h\82Í\83X\83\8c\83b\83h\83Z\81[\83t\82Å\82Í<b>\82 \82è\82Ü\82¹\82ñ\81B</b>
+ * <p>\8eó\90M\82Ì\91Ñ\88æ\82ð\90§\8cÀ\82·\82é\8b@\94\\82Í\8c»\8dÝ\8eÀ\91\95\82³\82ê\82Ä\82¢\82Ü\82¹\82ñ\81B
+ * <p>\8eg\82¢\95û
+ * <pre>
+ *             ByteBuffer buf =  ByteBuffer.allocate(BUFSIZE);
+ *             SocketChannel sc = serverSocketChannel.accept();
+ *             //\90§\8cÀ\91¬\93x\82ðbandWidth\82É\90Ý\92è
+ *             SocketChannelWriter     scw = new SocketChannelWriter(sc,bandWidth);
+ *             while(//\83o\83b\83t\83@\81[\82É\83f\81[\83^\82ð\93Ç\82Ý\8d\9e\82Þ){
+ *                     long nextTime = scw.write(buf);
+ *                     sleep(nextTime);
+ *             }
+ * </pre>
+ * 
+ * 
+ * @version 0.9
+ * @author senju
+ *
+ */
+
+
+public class SocketChannelWriter{
+
+       private SocketChannel channel;
+
+       private BandWidthController c;
+
+       /**
+        * SocketChannelWriter\82ð\90\90¬\82µ\82Ü\82·\81B
+        * @param channel               \83f\81[\83^\82Ì\91\97\90M\82ð\8ds\82¤\83`\83\83\83l\83\8b
+        * @param bandWidth     \90§\8cÀ\91¬\93x(bit per second)
+        */
+       public SocketChannelWriter(SocketChannel channel, double bandWidth) {
+               this.channel = channel;
+               c = new BandWidthController();
+               c.setBandWidth(bandWidth);
+       }
+
+       /**\90§\8cÀ\91¬\93x\82ð\95Ô\82µ\82Ü\82·\81B
+        * @return      \8c»\8dÝ\90Ý\92è\82³\82ê\82Ä\82¢\82é\90§\8cÀ\91¬\93x(bit per second)
+        */
+       public double getBandWidth() {
+               return c.getBandWidth();
+       }
+
+       /**\90§\8cÀ\91¬\93x\82ð\95Ï\8dX\82µ\82Ü\82·\81B
+        * @param bandWidth
+        */
+       public void setBandWidth(double bandWidth) {
+               c.setBandWidth(bandWidth);
+       }
+
+       
+       /**<p>\91Ñ\88æ\90§\8cÀ\82ð\82©\82¯\82½\91\97\8fo\82ð\8ds\82¢\82Ü\82·\81B
+        * <p>\82±\82Ì\83\81\83\\83b\83h\8cÄ\82Ñ\8fo\82µ\82ª\83u\83\8d\83b\83N\82³\82ê\82é\82±\82Æ\82Í\82 \82è\82Ü\82¹\82ñ\81B
+        * <p>\96ß\82è\92l\82Í\96³\8e\8b\82µ\82Ä\82à\91Ñ\88æ\90§\8cÀ\82Í\8ds\82í\82ê\82Ü\82·\82ª\81A\95s\97v\82È\82b\82o\82t\83\8a\83\\81[\83X\82Ì\8fÁ\94ï\82ð
+        * \94ð\82¯\82é\82½\82ß\82É\82Í\96ß\82è\92l\82ð\97\98\97p\82µ\82Ä\82­\82¾\82³\82¢\81B
+        * 
+        * @param buffer \91\97\8fo\82·\82é\83f\81[\83^\82ª\93ü\82Á\82½\83o\83b\83t\83@\81B
+        * <p>\90§\8cÀ\91¬\93x\82ðbyte\92P\88Ê\82É\95Ï\8dX\82µ\82½\8e\9e\82Ì10\95ª\82Ì\82P\88È\8fã\82Ì\83T\83C\83Y\82ª\90\84\8f§\82³\82ê\82Ü\82·\81B
+        * <p>\82Â\82Ü\82ègetBandWidth() / 8 / 10 \88È\8fã\82Å\82·\81B
+        * 
+        * @return      \8e\9f\89ñ\82±\82Ì\83\81\83\\83b\83h\82ð\8cÄ\82Ñ\8fo\82·\82Ü\82Å\82Ì\8e\9e\8aÔ\82ð\83~\83\8a\95b\82Å\95Ô\82µ\82Ü\82·\81B<br>\82Â\82Ü\82è
+        * \81u\96ß\82è\92l\83~\83\8a\95b\81v\8co\89ß\82µ\82Ä\82©\82ç\91±\82«\82Ì\83f\81[\83^\82ð\91\97\8fo\82µ\82Ä\82­\82¾\82³\82¢\81B
+        * <p>\82±\82Ì\96ß\82è\92l\82Ì\8e\9e\8aÔ\82ª\8co\89ß\82µ\82È\82¢\82¤\82¿\82É\8dÄ\82Ñ\82±\82Ì\83\81\83\\83b\83h\82ð\8cÄ\82Ñ\8fo\82µ\82Ä\82à
+        * \82¨\82»\82ç\82­0\83o\83C\83g\82Ì\91\97\8fo\82ª\8ds\82í\82ê\82Ü\82·\81B\82æ\82Á\82Ä\93K\90Ø\82É\91Ñ\88æ\90§\8cÀ\82Í\8ds\82í\82ê\82Ü\82·\82ª\82b\82o\82t
+        * \83\8a\83\\81[\83X\82ð\96³\91Ê\82É\8fÁ\94ï\82·\82é\82¾\82¯\82È\82Ì\82Å\81A(write()\82Í\8cÄ\82Ñ\8fo\82³\82ê\82é\82Æ\95K\82¸\81A\89½\83o\83C\83g\91\97\8fo
+        * \82·\82é\82×\82«\82©\82Ì\8cv\8eZ\82ð\8ds\82¢\82Ü\82·\81B)\82±\82Ì\8e\9e\8aÔ\82Ì\8aÔ\91\97\8fo\83X\83\8c\83b\83h\82ðsleep()\82³\82¹\82é\82È\82è
+        * \82Ì\8f\88\97\9d\82ð\8ds\82¤\82±\82Æ\82ª\90\84\8f§\82³\82ê\82Ü\82·\81B
+        * 
+        * 
+        * @throws IOException\81@SocketChannel\82ª\97á\8aO\82ð\94­\90\82³\82¹\82½\8fê\8d\87\81B
+        */
+       public long write(ByteBuffer buffer) throws IOException {
+               int writtenSize = 0;
+               int size = buffer.remaining();
+               SizeAndInterval si = c.preWrite(buffer.capacity());
+               try {
+                       if (si.getSize() == 0)
+                               c.postWrite(0);
+                       else if (si.getSize() >= size || si.getSize() == -1) {
+                               writtenSize = channel.write(buffer);
+                               c.postWrite(writtenSize);
+                       } else {
+                               int limit = buffer.limit();
+                               buffer.limit(buffer.position() + si.getSize());
+                               writtenSize = channel.write(buffer);
+
+                               c.postWrite(writtenSize);
+                               buffer.limit(limit);
+                       }
+               } catch (AsymmetricalCallException e) {
+                       e.printStackTrace();
+               }
+       
+               return si.getInterval();
+       }
+
+}