UNPKG

ndn-js

Version:

A JavaScript client library for Named Data Networking

290 lines (243 loc) 12.8 kB
<?xml version = "1.0" encoding="utf-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> <!-- * Copyright (C) 2014-2019 Regents of the University of California. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * A copy of the GNU Lesser General Public License is in the file COPYING. --> <html xmlns = "http://www.w3.org/1999/xhtml"> <meta charset="UTF-8"> <head> <title>NDN Get File via WebSocket</title> <script type="text/javascript" src="../../build/ndn.js"></script> <script type="text/javascript"> hostip = "localhost"; var face = new Face({port:9696,host:hostip}); /////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * Context for calling expressInterest to fetch big file. */ var ContentContext = function ContentContext(face, T0) { this.T0 = T0; // start time this.face = face; this.totalBlocks = 0; // total # of segments delivered to usr; // TODO: in this test script we simply discard the content after it is received // should consider some way to buffer the whole data in future refactor --- SWT // We should always start with the first element so the first data packet object cannot be ooo data //this.firstReceivedSegmentNumber = null; //this.firstReceivedData = null; // statistic counters this.ooo_count = 0; // out-of-order data packet object counter; // when this counter reaches 3, apply fast retransmission alg. this.pkt_recved = 0; // total # of data packet object received this.timed_out = 0; // totle # of timed out interest this.interest_sent = 1; // there is an initial interest before calling the callback this.dups = 0; // total # of dup content segments this.max_window = 32; // max window size this.max_retrans = 5; // max # of trial before give up; if we fail on one segment, the entire process is aborted this.snd_una = 0; // pointer to unacked segments this.snd_wnd = 1; // current window size this.snd_nxt = 1; // pointer to next interest to be sent this.ooo_table_size = 128; this.ooo_table = []; // hash table to mark ooo segments this.terminated = false; // Set this flag after we receive all the segments; }; ContentContext.prototype.expressInterest = function(name) { var thisContext = this; this.face.expressInterest (name, function(interest, data) { thisContext.onData(interest, data); }, function(interest) { thisContext.onTimeout(interest); }); }; ContentContext.prototype.onTimeout = function(interest) { this.pkt_recved++; if (this.terminated == false) { this.timed_out++; // Reduce window size to 1 this.snd_wnd = 1; // Retransmit interest for this segment this.expressInterest(interest.getName()); //console.log("Resend interest sent for " + interest.getName().toUri()); document.getElementById('content').innerHTML += "<p>Resend interest sent for " + interest.getName().toUri() + "</p>"; this.interest_sent++; document.getElementById('content').innerHTML += "<p>Interest " + interest.getName().toUri() + " time out.</p>"; document.getElementById('content').innerHTML += "<p>Total number of blocks: " + this.totalBlocks + "</p>"; document.getElementById('content').innerHTML += "<p>Total number of packets: " + this.pkt_recved + "</p>"; document.getElementById('content').innerHTML += "<p>Total number of dup segments: " + this.dups + "</p>"; document.getElementById('content').innerHTML += "<p>Total number of interest sent: " + this.interest_sent + "</p>"; document.getElementById('content').innerHTML += "<p>Total number of time-out interest: " + this.timed_out + "</p>"; document.getElementById('content').innerHTML += "<p>SND_UNA: " + this.snd_una + "</p>"; document.getElementById('content').innerHTML += "<p>SND_WND: " + this.snd_wnd + "</p>"; document.getElementById('content').innerHTML += "<p>SND_NXT: " + this.snd_nxt + "</p>"; } }; ContentContext.prototype.onData = function(interest, data) { this.pkt_recved++; if (data.getContent().isNull()) { console.log("data content is null"); return; } // Use the segmentNumber to load multiple segments. var segmentNumber = data.getName().get(-1).toSegment(); // Process received data here... // Count content length //nameStr = escape(data.getName().toUri()); //document.getElementById('content').innerHTML += "<p>Name string: " + nameStr + "</p>"; //document.getElementById('content').innerHTML += "<p>Content buffer length: " + data.getContent().size() + "</p>"; /* // Check for the special case if the saved content is for the next segment that we need. if (this.firstReceivedData != null && this.firstReceivedSegmentNumber == segmentNumber + 1) { // Substitute the saved data send its content and keep going. data = this.firstReceivedData; segmentNumber = segmentNumber + 1; // Clear firstReceivedData to save memory. this.firstReceivedData = null; // Process received data here... // Count content length //nameStr = escape(data.getName().toUri()); //document.getElementById('content').innerHTML += "<p>Name string: " + nameStr + "</p>"; //document.getElementById('content').innerHTML += "<p>Content buffer length: " + data.getContent().size() + "</p>"; this.totalBlocks++; } */ // Record final seg# if present var finalSegmentNumber = null; if (data.getMetaInfo() != null && data.getMetaInfo().getFinalBlockId().getValue().size() > 0) finalSegmentNumber = data.getMetaInfo().getFinalBlockId().toSegment(); // Check for out-of-order segment if (segmentNumber != this.snd_una) { //console.log("Out-of-order segment #" + segmentNumber + " received."); document.getElementById('content').innerHTML += "<p>Out-of-order segment #" + segmentNumber + " received.</p>"; this.ooo_count++; if (segmentNumber >= this.snd_nxt || segmentNumber < this.snd_una) { // Discard segment that is out of window //console.log("Out-of-window segment #" + segmentNumber); document.getElementById('content').innerHTML += "<p>Out-of-window segment #" + segmentNumber + "</p>"; return; } // Mark this segment in hash table var slot = segmentNumber % this.ooo_table_size; this.ooo_table[slot] = segmentNumber; if (this.ooo_count == 3) { // Fast retransmit // TODO: expressInterest for seg# = this.snd_una //this.snd_wnd = Math.floor(this.snd_wnd / 2) + 3; } else if (this.ooo_count > 3) { //this.snd_wnd++; // TODO: send a new interest if allowed by snd_wnd // SWT: what if we never receive the first unacked segment??? } return; } // In-order segment; slide window forward this.snd_una++ this.totalBlocks++; var slot = this.snd_una % this.ooo_table_size; while (this.ooo_table[slot] != undefined) { // continue to move forward until we reach a hole in the seg# sequence this.ooo_table[slot] = undefined; this.snd_una++; this.totalBlocks++; slot = this.snd_una % this.ooo_table_size; } if (finalSegmentNumber != null && this.snd_una == finalSegmentNumber + 1) { // All blocks before final block, including final block, is received. Mission complete. // Record stop time and print statistic result this.terminated = true; var T1 = new Date(); document.getElementById('content').innerHTML += "<p>Final block received.</p>"; document.getElementById('content').innerHTML += "<p>Time elapsed: " + (T1 - this.T0) + " ms</p>"; document.getElementById('content').innerHTML += "<p>Total number of blocks: " + this.totalBlocks + "</p>"; document.getElementById('content').innerHTML += "<p>Total number of packets: " + this.pkt_recved + "</p>"; document.getElementById('content').innerHTML += "<p>Total number of dup segments: " + this.dups + "</p>"; document.getElementById('content').innerHTML += "<p>Total number of interest sent: " + this.interest_sent + "</p>"; document.getElementById('content').innerHTML += "<p>Total number of time-out interest: " + this.timed_out + "</p>"; document.getElementById('content').innerHTML += "<p>SND_UNA: " + this.snd_una + "</p>"; document.getElementById('content').innerHTML += "<p>SND_WND: " + this.snd_wnd + "</p>"; document.getElementById('content').innerHTML += "<p>SND_NXT: " + this.snd_nxt + "</p>"; return; } // Adjust window size if (this.snd_wnd < this.max_window) { this.snd_wnd++; //console.log("Window size after adjust: " + this.snd_wnd); } // Send the next interest if allowed by snd_wnd var nextNameComponents = data.getName().components.slice(0, data.getName().size() - 1); //console.log("SND_UNA: " + this.snd_una); //console.log("SND_NXT: " + this.snd_nxt); while (this.snd_nxt - this.snd_una < this.snd_wnd) { // Make a name for the next segment and get it. var segmentNumberPlus1 = DataUtils.nonNegativeIntToBigEndian(this.snd_nxt); // Put a 0 byte in front. var nextSegmentNumber = new Uint8Array(segmentNumberPlus1.length + 1); nextSegmentNumber.set(segmentNumberPlus1, 1); nextNameComponents.push(nextSegmentNumber); var nextName = new Name(nextNameComponents); this.expressInterest(nextName); //console.log("Interest sent for seg # " + this.snd_nxt + " name " + nextName.toUri()); this.interest_sent++; this.snd_nxt++; nextNameComponents.pop(); // Remove segment number from components } }; /* * Convert the big endian Uint8Array to an unsigned int. * Don't check for overflow. */ function ArrayToNum(bytes) { var result = 0; for (var i = 0; i < bytes.length; ++i) { result = result * 10; result += (bytes[i] - 48); } return result; } /* * Convert the int value to a new big endian Uint8Array and return. * If value is 0 or negative, return Uint8Array(0). */ function NumToArray(value) { value = Math.round(value); if (value <= 0) return new Uint8Array(0); numString = value.toString(); var size = numString.length; var result = new Uint8Array(size); for (i = 0; i < size; i++) { result[i] = numString.charCodeAt(i); } return result; } function run() { document.getElementById('content').innerHTML += "<p>Started...</p>"; var name = new Name(document.getElementById('interest').value); var context = new ContentContext(face, new Date()); context.expressInterest(name); } </script> </head> <body > <form> Please Enter an Interest:<br /> <input id="interest" type="text" name="INTEREST" size="50" value="/wentao.shang/mars.jpg/%00" /> </form> <button onclick="run()">Fetch Content</button> <p id="content">Result: <br/></p> </body> </html>