KAD算法及实现 郝伟 2020/06/03
1. 前言
KAD是一种基于离散值的随机组网算法,本代码主要用于Kad算法的模拟测试,以理解其工作原理。
2. 代码解释
在主函数中,首先会生成一个随机的Kad网络,然后通过输入起点ID和终点ID,返回查找过程。本Kad网络的容量为 2^8^,即共256个节点。
3. 源代码
// package test;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
import static java.lang.System.out;
import java.io.IOException;
public class KadNode {
static Random rand = new Random(0);
static ArrayList<KadNode> nodes = new ArrayList<KadNode>();
public static void main(String[] args) throws IOException {
// create nodes.
for (int i = 0; i < 256; i++)
nodes.add(new KadNode(i));
// create neighbors
for (int i = 0; i < 100000; i++)
nodes.get(rand.nextInt(nodes.size())).ping(nodes.get(rand.nextInt(nodes.size())));
// print nodes
for (KadNode node : nodes)
System.out.println(node);
// by-hand testing
Scanner inp = new Scanner(System.in);
while (true) {
System.out.println("Please Input source id and target id:\n");
String input = inp.next();
if (input.equals("exit"))
break;
int srcid = Integer.parseInt(input.split(",")[0]);
int tarid = Integer.parseInt(input.split(",")[1]);
KadNode src = nodes.get(srcid);
System.out.printf("Search %d on %d...\n", tarid, srcid);
while (true) {
int nid = src.findNode(tarid);
if (nid > -1)
src = nodes.get(nid);
System.out.println(" -> found " + nid);
if (nid == -1 || nid - tarid == 0)
break;
}
}
}
public int id = 0;
public ArrayList<ArrayList<KadNode>> buckets = new ArrayList<ArrayList<KadNode>>();
public static final int BitLength = 8;
static int[] maxsizes = { 0, 1, 2, 4, 8, 8, 8, 8, 8, 8 };
static String[] bstr = { "00000000", "00000001", "00000010", "00000011", "00000100", "00000101", "00000110",
"00000111", "00001000", "00001001", "00001010", "00001011", "00001100", "00001101", "00001110", "00001111",
"00010000", "00010001", "00010010", "00010011", "00010100", "00010101", "00010110", "00010111", "00011000",
"00011001", "00011010", "00011011", "00011100", "00011101", "00011110", "00011111", "00100000", "00100001",
"00100010", "00100011", "00100100", "00100101", "00100110", "00100111", "00101000", "00101001", "00101010",
"00101011", "00101100", "00101101", "00101110", "00101111", "00110000", "00110001", "00110010", "00110011",
"00110100", "00110101", "00110110", "00110111", "00111000", "00111001", "00111010", "00111011", "00111100",
"00111101", "00111110", "00111111", "01000000", "01000001", "01000010", "01000011", "01000100", "01000101",
"01000110", "01000111", "01001000", "01001001", "01001010", "01001011", "01001100", "01001101", "01001110",
"01001111", "01010000", "01010001", "01010010", "01010011", "01010100", "01010101", "01010110", "01010111",
"01011000", "01011001", "01011010", "01011011", "01011100", "01011101", "01011110", "01011111", "01100000",
"01100001", "01100010", "01100011", "01100100", "01100101", "01100110", "01100111", "01101000", "01101001",
"01101010", "01101011", "01101100", "01101101", "01101110", "01101111", "01110000", "01110001", "01110010",
"01110011", "01110100", "01110101", "01110110", "01110111", "01111000", "01111001", "01111010", "01111011",
"01111100", "01111101", "01111110", "01111111", "10000000", "10000001", "10000010", "10000011", "10000100",
"10000101", "10000110", "10000111", "10001000", "10001001", "10001010", "10001011", "10001100", "10001101",
"10001110", "10001111", "10010000", "10010001", "10010010", "10010011", "10010100", "10010101", "10010110",
"10010111", "10011000", "10011001", "10011010", "10011011", "10011100", "10011101", "10011110", "10011111",
"10100000", "10100001", "10100010", "10100011", "10100100", "10100101", "10100110", "10100111", "10101000",
"10101001", "10101010", "10101011", "10101100", "10101101", "10101110", "10101111", "10110000", "10110001",
"10110010", "10110011", "10110100", "10110101", "10110110", "10110111", "10111000", "10111001", "10111010",
"10111011", "10111100", "10111101", "10111110", "10111111", "11000000", "11000001", "11000010", "11000011",
"11000100", "11000101", "11000110", "11000111", "11001000", "11001001", "11001010", "11001011", "11001100",
"11001101", "11001110", "11001111", "11010000", "11010001", "11010010", "11010011", "11010100", "11010101",
"11010110", "11010111", "11011000", "11011001", "11011010", "11011011", "11011100", "11011101", "11011110",
"11011111", "11100000", "11100001", "11100010", "11100011", "11100100", "11100101", "11100110", "11100111",
"11101000", "11101001", "11101010", "11101011", "11101100", "11101101", "11101110", "11101111", "11110000",
"11110001", "11110010", "11110011", "11110100", "11110101", "11110110", "11110111", "11111000", "11111001",
"11111010", "11111011", "11111100", "11111101", "11111110", "11111111", };
public KadNode() {
id = rand.nextInt(256);
for (int i = 0; i < 9; i++)
buckets.add(new ArrayList<KadNode>());
}
public KadNode(int id) {
this.id = id;
for (int i = 0; i < 9; i++)
buckets.add(new ArrayList<KadNode>());
}
// Returns the bucket id of the specified node n.
public int getBucketID(KadNode n) {
return getBucketK(n.id, getDistance(n.id, id));
}
// Returns the bucket id of the specified node id1 with the id2.
public int getBucketByID(int id1, int id2) {
return getBucketK(id1, id1 ^ id2);
}
/**
* Return the number of k-th bucket, i.e the value of k.
*
* @param id The node id.
* @param distance The xor result of node id and target id.
* @return
*/
public static int getBucketK(int id, int distance) {
int d = distance, v = 0b10000000, k = 8;
do {
if ((d & v) > 0)
break;
v = v >> 1;
k--;
} while (k > 0);
return k;
}
public static int getDistance(int id1, int id2) {
return id1 ^ id2;
}
static void test1() {
KadNode n1 = new KadNode();
KadNode n2 = new KadNode();
for (int i = 0; i < 256; i++) {
n2.id = i;
out.println(bstr[n1.id] + " to " + bstr[i] + " -> " + n1.getBucketID(n2));
}
}
public void ping(KadNode node) {
if (node != null && node.id != this.id)
node.accept(this);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ID: " + id);
for (int i = 0; i < buckets.size(); i++) {
sb.append(" " + i + ": ");
for (KadNode node : buckets.get(i))
sb.append(node.id + " -> ");
sb.append("END\n");
}
return sb.toString();
}
private void accept(KadNode node) {
int bid = this.getBucketID(node);
// out.println("bid = " + bid + ", buckets.size() = " + buckets.size());
ArrayList<KadNode> bk = buckets.get(bid);
if (bk.contains(node)) {
bk.remove(node);
bk.add(node);
} else {
if (bk.size() < maxsizes[bid])
bk.add(node);
else {
// TODO: evict several least recently nodes that do not response
}
}
}
// find node by id
public int findNode(int id) {
int bid = getBucketByID(this.id, id);
return buckets.get(bid).size() == 0 ? -1
: buckets.get(bid).stream().sorted((n1, n2) -> Integer.compare(n1.id ^ id, n2.id ^ id))
.findFirst().get().id;
}
}
4. 数据
ID: 0 0: END
1: 1 -> END
2: 2 -> 3 -> END
3: 5 -> 6 -> 7 -> 4 -> END
4: 10 -> 11 -> 8 -> 12 -> 9 -> 15 -> 14 -> END
5: 27 -> 23 -> 29 -> 21 -> 28 -> 18 -> 24 -> 25 -> END
6: 60 -> 55 -> 45 -> 56 -> 42 -> 61 -> 47 -> 35 -> END
7: 107 -> 87 -> 85 -> 73 -> 83 -> 104 -> 89 -> 71 -> END
8: 153 -> 244 -> 193 -> 148 -> 129 -> 144 -> 205 -> 200 -> END
ID: 1 0: END
1: 0 -> END
2: 3 -> 2 -> END
3: 6 -> 4 -> END
4: 9 -> 13 -> 14 -> 15 -> 10 -> 12 -> 8 -> 11 -> END
5: 20 -> 19 -> 17 -> 28 -> 22 -> 16 -> 27 -> 29 -> END
6: 43 -> 41 -> 36 -> 48 -> 37 -> 63 -> 35 -> 59 -> END
7: 78 -> 70 -> 95 -> 101 -> 82 -> 94 -> 104 -> 66 -> END
8: 164 -> 137 -> 199 -> 248 -> 158 -> 237 -> 170 -> 207 -> END
ID: 2 0: END
1: 3 -> END
2: 0 -> END
3: 7 -> 6 -> 5 -> END
4: 12 -> 14 -> 15 -> 10 -> 8 -> 13 -> 9 -> END
5: 31 -> 16 -> 30 -> 22 -> 29 -> 18 -> 27 -> 21 -> END
6: 42 -> 41 -> 50 -> 36 -> 48 -> 47 -> 52 -> 63 -> END
7: 118 -> 114 -> 83 -> 111 -> 70 -> 77 -> 119 -> 123 -> END
8: 212 -> 187 -> 213 -> 236 -> 243 -> 252 -> 205 -> 139 -> END
ID: 3 0: END
1: 2 -> END
2: 1 -> 0 -> END
3: 7 -> 4 -> 5 -> END
4: 15 -> 13 -> 11 -> 10 -> 8 -> 14 -> 9 -> 12 -> END
5: 29 -> 22 -> 17 -> 18 -> 27 -> 25 -> 16 -> 26 -> END
6: 40 -> 57 -> 49 -> 36 -> 45 -> 33 -> 35 -> 37 -> END
7: 105 -> 67 -> 86 -> 110 -> 117 -> 79 -> 127 -> 73 -> END
8: 247 -> 231 -> 232 -> 135 -> 139 -> 209 -> 211 -> 204 -> END
#(中间省略约2500行)
ID: 251 0: END
1: 250 -> END
2: 249 -> 248 -> END
3: 254 -> 253 -> 252 -> END
4: 244 -> 242 -> 245 -> 243 -> 246 -> END
5: 225 -> 231 -> 226 -> 239 -> 234 -> 236 -> 232 -> 227 -> END
6: 214 -> 204 -> 209 -> 220 -> 196 -> 202 -> 197 -> 222 -> END
7: 158 -> 144 -> 133 -> 191 -> 189 -> 187 -> 128 -> 172 -> END
8: 31 -> 101 -> 126 -> 80 -> 20 -> 65 -> 97 -> 95 -> END
ID: 252 0: END
1: 253 -> END
2: 255 -> 254 -> END
3: 250 -> 249 -> 248 -> 251 -> END
4: 240 -> 245 -> 247 -> 244 -> 246 -> 242 -> END
5: 230 -> 227 -> 233 -> 238 -> 232 -> 224 -> 236 -> 229 -> END
6: 207 -> 215 -> 196 -> 218 -> 208 -> 213 -> 219 -> 203 -> END
7: 179 -> 134 -> 154 -> 141 -> 177 -> 132 -> 142 -> 164 -> END
8: 64 -> 27 -> 0 -> 9 -> 97 -> 54 -> 102 -> 25 -> END
ID: 253 0: END
1: END
2: 254 -> END
3: 249 -> 250 -> 248 -> 251 -> END
4: 246 -> 240 -> 242 -> 243 -> 247 -> 244 -> 241 -> END
5: 228 -> 238 -> 237 -> 233 -> 232 -> 226 -> 227 -> 230 -> END
6: 204 -> 208 -> 199 -> 209 -> 217 -> 220 -> 219 -> 195 -> END
7: 175 -> 148 -> 177 -> 129 -> 131 -> 159 -> 166 -> 134 -> END
8: 123 -> 41 -> 46 -> 58 -> 75 -> 79 -> 23 -> 82 -> END
ID: 254 0: END
1: END
2: 252 -> END
3: 251 -> 250 -> 249 -> 248 -> END
4: 245 -> 244 -> 246 -> 242 -> 241 -> 240 -> END
5: 239 -> 226 -> 224 -> 225 -> 231 -> 238 -> 228 -> 233 -> END
6: 206 -> 221 -> 204 -> 199 -> 193 -> 216 -> 217 -> 194 -> END
7: 151 -> 138 -> 141 -> 180 -> 164 -> 158 -> 147 -> 128 -> END
8: 19 -> 18 -> 106 -> 34 -> 74 -> 76 -> 101 -> 71 -> END
ID: 255 0: END
1: 254 -> END
2: 253 -> 252 -> END
3: 251 -> 248 -> 249 -> END
4: 245 -> 244 -> 246 -> 240 -> 247 -> 243 -> 241 -> 242 -> END
5: 224 -> 231 -> 229 -> 225 -> 238 -> 234 -> 227 -> 233 -> END
6: 222 -> 197 -> 196 -> 206 -> 193 -> 207 -> 195 -> 201 -> END
7: 149 -> 164 -> 143 -> 155 -> 138 -> 160 -> 146 -> 166 -> END
8: 79 -> 90 -> 22 -> 38 -> 93 -> 61 -> 66 -> 70 -> END
Please Input source id and target id:
1,4
Search 4 on 1...
Looking for 4
-> found 4
Please Input source id and target id:
1,252
Search 252 on 1...
Looking for 252
-> found 248
-> found 252
Please Input source id and target id:
exit