部分代码来自于GitHub,词典文件为盗版,仅用于学习,禁止传播

Chord网络的模拟(90分)

(1)问题描述

Chord是一种非常经典的P2P结构化网络,可以在Chord上进行分布式P2P文件共享等应用。Chord网络的基本结构如图6-59所示,它是以分布式散列表为基础构建的一种逻辑网络。

分布式散列表(DHT)实际上是一个由大量结点分布式的共同维护的巨大散列表。散列表被分割成不连续的块,每个结点被分配给一个属于自己的散列块(一个散列值范围),并成为这个散列块的管理者,负责存储散列结果位于该散列块内的信息。DHT中使用的散列函数通常是加密散列函数(如MD5,SHA-1等),通过这些函数,一个对象的名字(如节点的ID或其IP地址)或关键词(如文件名)被映射为128位或160位的散列,如SHA-1(“202.38.64.1”)=24b92cb1d2b81a47472a93d06af3d85a42e463ea。一个采用DHT的系统内,所有计算结点、数据对象等被映射到一个空间内。对于图6-59中的Chord结构,每个计算节点根据其IP可以计算出其ID,如图中的N14。

每个文件根据其关键词可以计算出每个信息的ID,就是图中的K,如图中的K=hash(key)=54,这些K被放在Chord环中机器节点ID大于K且最近的K的节点,如图中将K=54的信息放在ID=56的节点N56上,将K=30和K=24的信息放在ID=32的节点N32上。

Chord结构主要支持如下操作:①Insert(key,V),即将关键词key对应的信息V对存放到节点ID大于K=hash(key)且离K最近的节点上,这样的ID可用Successor(K)表示,其中Successor(K)是从K开始顺时针方向距离K最近的节点。②Lookup(K),根据K查询相应的V,主要表现为根据Chord中节点的连接(上图中的节点间连线)路由到存放K的节点上,即节点ID=Successor(K)的节点,在该节点上可以找到K对应的V。③Update(K,new_V):根据K更新相应的V。④Join(NID):加入一个新节点,NID是节点的标识,如节点的IP地址,在Chord中加入一个节点需要建立相应的连接,需要移动信息数据,如上图中新加入一个节点N26,则需要将K=24移动到该节点。⑤Leave():某个节点主动离开Chord,在Chord中推出一个节点需要修改相应的连接,也需要移动某些信息数据,如上图中退出一个节点N14,则需要将K=10移动到节点N21。

Chord结构的一个非常重要的特点是如果每个节点仅维护其后继节点ID、IP地址等信息,则查询消息通过后继节点指针在圆环上传递,直到查询消息中包含的K落在某节点ID和它的后继节点ID之间,这样的查询速度太慢O(N),N为网络中节点数,如图6-60(a)所示。因此在基本Chord上,引入了一些能加快查询的finger表,finger表的结构如图6-60(b)表示,节点为ID的finger表中存放的是所有的(ID+2i)modNID的i从1开始且逐个增1的ID=Successor(ID+2i)的那些节点,每个i对应了finger表中的1项。有了finger表后,可以加速查询过程,对于路由中的任何一个节点ID,该节点选择的路由下一跳是finger表中满足(ID+2i)modN小于等于K且最接近K的那个i对应的表项,从这个表项中可以找到查询的下一跳,如图6-60(c)所示。

仔细分析可以发现,引入finger表后,查询K的路由跳数为O(logN),相比O(N)而言有很大的提高。

(2)课程设计目的

建立对Chord结构的认识,能用数据结构知识完成Chord结构的模拟。

(3)基本要求

①用数据结构知识设计和实现Chord网络结构。

②实现Chord结构上的Insert、Lookup、Update、Leave、Join五个操作。

③构建一个Chord的单机模拟应用,其中的数据信息可以自己定义,如可以定义key为一个一个的英语单词,而其对应的数据为该单词的英文解释。

④应模拟出各个操作的结果,尤其是模拟出Lookup的路由过程,模拟过程应该是可视的,即可以看到节点的连接,路由一跳一跳的过程,鼓励使用VC实现。

⑤用实验结果分析验证引入finger表后,查询K的路由跳数为O(logN)的理论结果。

(4)实现提示

可以查阅P2P中关于Chord的资料,其中用到的散列函数可以直接使用现有的散列函数,如SHA-1,可以直接下载使用散列函数的源代码。

代码:

头文件:

Chord.h

#include <iostream>
#include <vector>
#include <map>
#include <math.h>
#include <vector>using namespace std;class Node;class FingerTable {
public:vector<Node*> fingerTable;Node* local_node;int nodeId;FingerTable(int id, Node* node) {this->nodeId = id;this->local_node = node;}~FingerTable() {this->nodeId = -99;this->fingerTable.clear();}void printFingerTable();
};class Node {public:uint64_t id;Node* predecessor;std::map<int, int> local_keys;FingerTable *fingertable;Node(int id) {this->id = (int) id;this->predecessor = NULL;this->fingertable = new FingerTable(this->id, this);}~Node() {this->id = INT64_MIN;(this->local_keys).clear();}// Move keys (if any) to the newly added nodevoid moveKeys(Node* succ, int new_node_id) {map<int, int> m;map<int, int>::iterator iter;for (map<int, int>::iterator iter = succ->local_keys.begin();iter != succ->local_keys.end(); iter++) {if (iter->first <= new_node_id&& iter->first > succ->predecessor->id) {insert_key_local(iter->first, iter->second);} else {m.insert(pair<int, int>(iter->first, iter->second));}}succ->local_keys.clear();succ->local_keys = m;}// Node join operationvoid Join(Node* node) {if (node == NULL) {  // First node to joinfor (int i = 0; i < 8; i++) {fingertable->fingerTable.push_back(this);}predecessor = this;} else {for (int i = 0; i < 8; i++) {fingertable->fingerTable.push_back(this);}// Find successor to attach toNode* succ = node->find_successor(id);// Update node's successor to point to the successorfingertable->fingerTable[0] = succ;// Update predecessor's successor to selfsucc->predecessor->fingertable->fingerTable[0] = this;// Update predecessor to successor's old predecessorpredecessor = succ->predecessor;// move keys on the successor before changing predecessormoveKeys(succ, id);// Update successor's predecssor to selfsucc->predecessor = this;// update finger table// fingerTable[0] is always the successorcreateFingerTable();}}// creates the finger tablevoid createFingerTable() {for (int i = 1; i < fingertable->fingerTable.size(); i++) {Node* ptr = this;int flag = 0;for (int j = 0; j < pow(2, i); j++) {ptr = ptr->fingertable->fingerTable[0];if (ptr == this) {flag = 1;break;}}if (flag == 0) {fingertable->fingerTable[i] = ptr;}}}// stabilize the finger tablesvoid stabilize() {for (int i = 1; i < fingertable->fingerTable.size(); i++) {fingertable->fingerTable[i]->createFingerTable();}}// Find SuccessorNode* find_successor(int id) {if (this->id == id) {return this;}else if (this->id > id) {return this;}else if(this->id < id && this->fingertable->fingerTable[0]->id <= this->id) {return this->fingertable->fingerTable[0];}else {return fingertable->fingerTable[0]->find_successor(id);}}// Search a key value pairstring LookUp(int key) {int node_id = 0;string ret_val;cout << "\n Searching Key " << key << " on node " << id << endl;node_id = local_key_lookup(key);if (node_id >= 0) {ret_val = " Found value - " + to_string(node_id) + " on Node - "+ to_string(id) + "\n";} else {for (int i = 0; i < fingertable->fingerTable.size(); i++) {node_id = fingertable->fingerTable[i]->local_key_lookup(key);if (node_id >= 0) {ret_val =  " Found value - " + to_string(node_id) + " on Node - "+ to_string(fingertable->fingerTable[i]->id) + "\n";break;}else {cout << "Found None" << endl;}}}return ret_val;}// Insert keyvoid Insert(int key, int value) {if (key < 0) {cerr << "\n *** Error Key is less than 0 *** \n";return;}Node* succ = this->fingertable->fingerTable[0];if (succ->id <= id && id <= key) {succ->insert_key_local(key, value);}else if (predecessor->id > id && key > predecessor->id) {insert_key_local(key, value);}else {while (succ->id < key) {succ = succ->fingertable->fingerTable[0];}succ->insert_key_local(key, value);}}// Insert a key on this nodevoid insert_key_local(int key, int value) {if (!key) {cout << "No key provided to insert_key!" << endl;}local_keys.insert(pair<int, int>(key, value));}// Search a key locallyint local_key_lookup(int key) {cout << " Node " << this->id << " searched" << endl;int node = -1;for (int i = 0; i < local_keys.size(); i++) {if (local_keys.find(key)->first == key) {node =  local_keys.find(key)->second;}}return node;}// Leave the chord ring and automatically move the info on itvoid Leave() {Node* succ = this->fingertable->fingerTable[0];Node* pred = this->predecessor;// Connect the predecessor's successor to this's successorpred->fingertable->fingerTable[0] = succ;// Connect the successor's predecessor to this's predecessorsucc->predecessor = pred;// Rest of the nodes recreating the Finger Tablesucc->createFingerTable();pred->createFingerTable();// // Insert the value to the rest nodesfor (map<int, int>::iterator iter = this->local_keys.begin(); iter != this->local_keys.end(); iter++) {succ->Insert(iter->first, iter->second);}}
};// Print Finger Table
void FingerTable::printFingerTable() {cout << "\n**** Node ID : " << this->nodeId << " ****";cout << "\nFingerTable\n";for (int i = 0; i < fingerTable.size(); i++) {if (i == 0 || (nodeId != fingerTable[i]->fingertable->nodeId)) {cout << i + 1 << " : " << fingerTable[i]->fingertable->nodeId<< "\n";}}cout << "\nKeys : ";for (map<int, int>::iterator iter = local_node->local_keys.begin();iter != local_node->local_keys.end(); iter++) {cout << iter->second << "  ";}cout << "\n**********************\n";
}

Chord_sha1.h

#include <bits/stdc++.h>
using namespace std;class Node;//Fingertable
//Fingertable表的[0]位永远为该结点后继
class FingerTable {
public:vector<Node*> fingerTable;//fingertableNode* local_node;//当前结点string nodeId;//当前结点的idFingerTable(string id, Node* node) {this->nodeId = id;this->local_node = node;}~FingerTable() {this->nodeId = "NULL";this->fingerTable.clear();}//打印当前结点的fingertable以及key值void printFingerTable();//打印当前结点的fingertablevoid printFingerTableWithoutKey();
};//Node
class Node {public:string id;//此节点的idNode* predecessor;//此节点的前驱std::map<string, string> local_keys;//此节点存储的所有key值FingerTable *fingertable;//此节点的fingertable(注意同样是个类)Node(string id) {this->id = id;this->predecessor = NULL;this->fingertable = new FingerTable(this->id, this);}~Node() {this->id = "NULL";(this->local_keys).clear();}//加入nodevoid Join(Node* node) {if (node == NULL) {  //第一个nodefor (int i = 0; i < 8; i++) {fingertable->fingerTable.push_back(this);}predecessor = this;} else {for (int i = 0; i < 8; i++) {fingertable->fingerTable.push_back(this);}//找到后继,即插入位置Node* succ = node->find_successor(id);//调整位置关系fingertable->fingerTable[0] = succ;succ->predecessor->fingertable->fingerTable[0] = this;predecessor = succ->predecessor;//调整keymoveKeys(succ, id);//更新后继的前驱为此节点succ->predecessor = this;//更新fingertablecreateFingerTable();}}//更新fingertablevoid stabilize() {for (int i = 1; i < fingertable->fingerTable.size(); i++) {fingertable->fingerTable[i]->createFingerTable();}}//寻找string LookUp(string key) {string value = "NULL";//存储寻找到的值string ret_val;//返回值cout << "Searching Key " << key << " on node " << id << endl;value = local_key_lookup(key);//当前节点搜寻if (value != "NULL") {ret_val = "Found value: " + value + " on Node: " + id + "\n";}//若未找到else {Node *t = this;bool b = false;//外层i循环作用为规定最大循环次数防止出现找不到的情况for (int i = 0; i < 100; i++) {b = false;int j;//j循环作用为在当前结点的fingertable中寻找目标idfor(j = 0; j < t->fingertable->fingerTable.size(); j++) {//当前结点的fingertable中某节点的id大于了寻找的idif(t->fingertable->fingerTable[j]->id >= key) {//若找到的是后继,则寻找id在当前结点的前面,所以更新结点为其前驱if(j == 0) {t = t->predecessor;}//若id不在当前结点前,即找到了,更新当前结点为fingertable中寻找到的结点的前一位else {t = t->fingertable->fingerTable[j - 1];b = true;//标记找到break;}}//防止数组越界//写的什么shiif(j < 8) {//fingertable中当前结点已找完(fingertable未满情况)if(t->fingertable->fingerTable[j]->id == t->fingertable->fingerTable[j + 1]->id) {break;}}}//若在当前结点的fingertable中未找到,则当前结点变为fingertable中的最后一个if(!b) {t = t->fingertable->fingerTable[j - 2];}// t->fingertable->printFingerTableWithoutKey();//不论是否找到,都在当前结点中搜寻value = t->fingertable->fingerTable[0]->local_key_lookup(key);//若找到if (value != "NULL") {ret_val =  "Found value: " + value + " on Node: " + t->fingertable->fingerTable[0]->id + "\n";break;}//若为找到else {cout << "Found None" << endl;// t = t->fingertable->fingerTable[0];//如果未找到且当前节点后继大于key,即后继再也没有此值了if(t->fingertable->fingerTable[0]->id > key) {ret_val =  "Can't Find\n";break;}}}}return ret_val;}//插入值void Insert(string key, string value) {//首先找到后继结点,用于判断以下的不同插入情况Node* succ = this->fingertable->fingerTable[0];//若插入结点(后继结点)小于当前结点且当前结点小于key,即当前结点在环的最后一位且key大于当前结点if (succ->id <= id && id <= key) {//则插入到环的第一位succ->insert_key_local(key, value);}//若当前结点的前驱大于当前结点且key大于前驱,即当前结点在环的第一位且key大于前驱else if (predecessor->id > id && key > predecessor->id) {//则插入到当前结点insert_key_local(key, value);}//       上面两个好像一样,但是我不想删了因为程序已经能跑了
//      我也忘了为什么要这样写,可能删了会有bug
//      反正我是写unity c#的,c++我也学不透,说实话这个实验的代码挺烂
//      实验验收这块代码略过就行
//      有人cv的话记得在实验前把这块删一下,顺便点个赞和收藏(づ ̄3 ̄)づ  ~~~❤
//
//        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                            _ooOoo_
//                           o8888888o
//                           88" . "88
//                           (| -_- |)
//                           O\  =  /O
//                        ____/`---'\____
//                      .'  \\|     |//  `.
//                     /  \\|||  :  |||//  \
//                    /  _||||| -:- |||||-  \
//                    |   | \\\  -  /// |   |
//                    | \_|  ''\---/''  |   |
//                    \  .-\__  `-`  ___/-. /
//                  ___`. .'  /--.--\  `. . __
//               ."" '<  `.___\_<|>_/___.'  >'"".
//              | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//              \  \ `-.   \_ __\ /__ _/   .-` /  /
//         ======`-.____`-.___\_____/___.-`____.-'======
//
//        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//不在环的边界情况下时else {//若后继结点小于key时,应继续寻找while (succ->id < key) {//后继结点向后移动succ = succ->fingertable->fingerTable[0];}//最后找到则插入succ->insert_key_local(key, value);}}//退出结点void Leave(string id) {find_successor(id)->_Leave();//寻找目标结点并退出stabilize();//退出后自动更新结点的fingertable}private: //移动Keys到新加入的node上void moveKeys(Node* succ, string new_node_id) {map<string, string> m;map<string, string>::iterator iter;for (map<string, string>::iterator iter = succ->local_keys.begin(); iter != succ->local_keys.end(); iter++) {if (iter->first <= new_node_id && iter->first > succ->predecessor->id) {insert_key_local(iter->first, iter->second);} else {m.insert(pair<string, string>(iter->first, iter->second));}}succ->local_keys.clear();succ->local_keys = m;}//创建fingertablevoid createFingerTable() {for (int i = 1; i < fingertable->fingerTable.size(); i++) {Node* ptr = this;int flag = 0;for (int j = 0; j < pow(2, i); j++) {ptr = ptr->fingertable->fingerTable[0];if (ptr == this) {flag = 1;break;}}if (flag == 0) {fingertable->fingerTable[i] = ptr;}}}//寻找某id的后继结点Node* find_successor(string id) {if (this->id == id) {return this;}else if (this->id > id) {return this;}else if(this->id < id && this->fingertable->fingerTable[0]->id <= this->id) {return this->fingertable->fingerTable[0];}else {return fingertable->fingerTable[0]->find_successor(id);}}//在当前结点中插入值void insert_key_local(string key, string value) {if (key == "NULL") {cout << "No key provided to insert_key!" << endl;}local_keys.insert(pair<string, string>(key, value));}//在当前结点的key中搜寻目标keystring local_key_lookup(string key) {cout << "Node " << this->id << " searched" << endl;string value = "NULL";for (int i = 0; i < local_keys.size(); i++) {if(local_keys.find(key)->first == key) {value = local_keys.find(key)->second;}}return value;}//结点退出代码(内部的)void _Leave() {//先保存删除结点的前驱后继Node* succ = this->fingertable->fingerTable[0];Node* pred = this->predecessor;//连接前驱和后继pred->fingertable->fingerTable[0] = succ;succ->predecessor = pred;//前驱和后继这两个结点重新建立fingertablesucc->createFingerTable();pred->createFingerTable();//将删除结点上的key和value插入到别的结点上for (map<string, string>::iterator iter = this->local_keys.begin(); iter != this->local_keys.end(); iter++) {succ->Insert(iter->first, iter->second);}}
};//打印当前结点的fingertable以及key值
void FingerTable::printFingerTable() {cout << "**** Node ID : " << this->nodeId << " ****" << endl;cout << "FingerTable" << endl;for (int i = 0; i < fingerTable.size(); i++) {if (i == 0 || (nodeId != fingerTable[i]->fingertable->nodeId)) {cout << i + 1 << " : " << fingerTable[i]->fingertable->nodeId << endl;}}cout << "Keys: " << endl;for (map<string, string>::iterator iter = local_node->local_keys.begin(); iter != local_node->local_keys.end(); iter++) {cout << iter->first << endl;}cout << "**********************" << endl;
}//打印当前结点的fingertable
void FingerTable::printFingerTableWithoutKey() {cout << "**** Node ID : " << this->nodeId << " ****" << endl;cout << "FingerTable" << endl;for (int i = 0; i < fingerTable.size(); i++) {if (i == 0 || (nodeId != fingerTable[i]->fingertable->nodeId)) {cout << i + 1 << " : " << fingerTable[i]->fingertable->nodeId << endl;}}cout << "**********************" << endl;
}

sha1.hpp

/*sha1.hpp - source code of============SHA-1 in C++============100% Public Domain.Original C Code-- Steve Reid <steve@edmweb.com>Small changes to fit into bglibs-- Bruce Guenter <bruce@untroubled.org>Translation to simpler C++ Code-- Volker Diels-Grabsch <v@njh.eu>Safety fixes-- Eugene Hopkinson <slowriot at voxelstorm dot com>Header-only library-- Zlatko Michailov <zlatko@michailov.org>
*/#ifndef SHA1_HPP
#define SHA1_HPP#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>class SHA1
{
public:SHA1();void update(const std::string &s);void update(std::istream &is);std::string final();static std::string from_file(const std::string &filename);private:uint32_t digest[5];std::string buffer;uint64_t transforms;
};static const size_t BLOCK_INTS = 16;  /* number of 32bit integers per SHA1 block */
static const size_t BLOCK_BYTES = BLOCK_INTS * 4;inline static void reset(uint32_t digest[], std::string &buffer, uint64_t &transforms)
{/* SHA1 initialization constants */digest[0] = 0x67452301;digest[1] = 0xefcdab89;digest[2] = 0x98badcfe;digest[3] = 0x10325476;digest[4] = 0xc3d2e1f0;/* Reset counters */buffer = "";transforms = 0;
}inline static uint32_t rol(const uint32_t value, const size_t bits)
{return (value << bits) | (value >> (32 - bits));
}inline static uint32_t blk(const uint32_t block[BLOCK_INTS], const size_t i)
{return rol(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i], 1);
}/** (R0+R1), R2, R3, R4 are the different operations used in SHA1*/inline static void R0(const uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
{z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5);w = rol(w, 30);
}inline static void R1(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
{block[i] = blk(block, i);z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5);w = rol(w, 30);
}inline static void R2(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
{block[i] = blk(block, i);z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5);w = rol(w, 30);
}inline static void R3(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
{block[i] = blk(block, i);z += (((w|x)&y)|(w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5);w = rol(w, 30);
}inline static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
{block[i] = blk(block, i);z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5);w = rol(w, 30);
}/** Hash a single 512-bit block. This is the core of the algorithm.*/inline static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t &transforms)
{/* Copy digest[] to working vars */uint32_t a = digest[0];uint32_t b = digest[1];uint32_t c = digest[2];uint32_t d = digest[3];uint32_t e = digest[4];/* 4 rounds of 20 operations each. Loop unrolled. */R0(block, a, b, c, d, e,  0);R0(block, e, a, b, c, d,  1);R0(block, d, e, a, b, c,  2);R0(block, c, d, e, a, b,  3);R0(block, b, c, d, e, a,  4);R0(block, a, b, c, d, e,  5);R0(block, e, a, b, c, d,  6);R0(block, d, e, a, b, c,  7);R0(block, c, d, e, a, b,  8);R0(block, b, c, d, e, a,  9);R0(block, a, b, c, d, e, 10);R0(block, e, a, b, c, d, 11);R0(block, d, e, a, b, c, 12);R0(block, c, d, e, a, b, 13);R0(block, b, c, d, e, a, 14);R0(block, a, b, c, d, e, 15);R1(block, e, a, b, c, d,  0);R1(block, d, e, a, b, c,  1);R1(block, c, d, e, a, b,  2);R1(block, b, c, d, e, a,  3);R2(block, a, b, c, d, e,  4);R2(block, e, a, b, c, d,  5);R2(block, d, e, a, b, c,  6);R2(block, c, d, e, a, b,  7);R2(block, b, c, d, e, a,  8);R2(block, a, b, c, d, e,  9);R2(block, e, a, b, c, d, 10);R2(block, d, e, a, b, c, 11);R2(block, c, d, e, a, b, 12);R2(block, b, c, d, e, a, 13);R2(block, a, b, c, d, e, 14);R2(block, e, a, b, c, d, 15);R2(block, d, e, a, b, c,  0);R2(block, c, d, e, a, b,  1);R2(block, b, c, d, e, a,  2);R2(block, a, b, c, d, e,  3);R2(block, e, a, b, c, d,  4);R2(block, d, e, a, b, c,  5);R2(block, c, d, e, a, b,  6);R2(block, b, c, d, e, a,  7);R3(block, a, b, c, d, e,  8);R3(block, e, a, b, c, d,  9);R3(block, d, e, a, b, c, 10);R3(block, c, d, e, a, b, 11);R3(block, b, c, d, e, a, 12);R3(block, a, b, c, d, e, 13);R3(block, e, a, b, c, d, 14);R3(block, d, e, a, b, c, 15);R3(block, c, d, e, a, b,  0);R3(block, b, c, d, e, a,  1);R3(block, a, b, c, d, e,  2);R3(block, e, a, b, c, d,  3);R3(block, d, e, a, b, c,  4);R3(block, c, d, e, a, b,  5);R3(block, b, c, d, e, a,  6);R3(block, a, b, c, d, e,  7);R3(block, e, a, b, c, d,  8);R3(block, d, e, a, b, c,  9);R3(block, c, d, e, a, b, 10);R3(block, b, c, d, e, a, 11);R4(block, a, b, c, d, e, 12);R4(block, e, a, b, c, d, 13);R4(block, d, e, a, b, c, 14);R4(block, c, d, e, a, b, 15);R4(block, b, c, d, e, a,  0);R4(block, a, b, c, d, e,  1);R4(block, e, a, b, c, d,  2);R4(block, d, e, a, b, c,  3);R4(block, c, d, e, a, b,  4);R4(block, b, c, d, e, a,  5);R4(block, a, b, c, d, e,  6);R4(block, e, a, b, c, d,  7);R4(block, d, e, a, b, c,  8);R4(block, c, d, e, a, b,  9);R4(block, b, c, d, e, a, 10);R4(block, a, b, c, d, e, 11);R4(block, e, a, b, c, d, 12);R4(block, d, e, a, b, c, 13);R4(block, c, d, e, a, b, 14);R4(block, b, c, d, e, a, 15);/* Add the working vars back into digest[] */digest[0] += a;digest[1] += b;digest[2] += c;digest[3] += d;digest[4] += e;/* Count the number of transformations */transforms++;
}inline static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS])
{/* Convert the std::string (byte buffer) to a uint32_t array (MSB) */for (size_t i = 0; i < BLOCK_INTS; i++){block[i] = (buffer[4*i+3] & 0xff)| (buffer[4*i+2] & 0xff)<<8| (buffer[4*i+1] & 0xff)<<16| (buffer[4*i+0] & 0xff)<<24;}
}inline SHA1::SHA1()
{reset(digest, buffer, transforms);
}inline void SHA1::update(const std::string &s)
{std::istringstream is(s);update(is);
}inline void SHA1::update(std::istream &is)
{while (true){char sbuf[BLOCK_BYTES];is.read(sbuf, BLOCK_BYTES - buffer.size());buffer.append(sbuf, (std::size_t)is.gcount());if (buffer.size() != BLOCK_BYTES){return;}uint32_t block[BLOCK_INTS];buffer_to_block(buffer, block);transform(digest, block, transforms);buffer.clear();}
}/** Add padding and return the message digest.*/inline std::string SHA1::final()
{/* Total number of hashed bits */uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;/* Padding */buffer += (char)0x80;size_t orig_size = buffer.size();while (buffer.size() < BLOCK_BYTES){buffer += (char)0x00;}uint32_t block[BLOCK_INTS];buffer_to_block(buffer, block);if (orig_size > BLOCK_BYTES - 8){transform(digest, block, transforms);for (size_t i = 0; i < BLOCK_INTS - 2; i++){block[i] = 0;}}/* Append total_bits, split this uint64_t into two uint32_t */block[BLOCK_INTS - 1] = (uint32_t)total_bits;block[BLOCK_INTS - 2] = (uint32_t)(total_bits >> 32);transform(digest, block, transforms);/* Hex std::string */std::ostringstream result;for (size_t i = 0; i < sizeof(digest) / sizeof(digest[0]); i++){result << std::hex << std::setfill('0') << std::setw(8);result << digest[i];}/* Reset for next run */reset(digest, buffer, transforms);return result.str();
}inline std::string SHA1::from_file(const std::string &filename)
{std::ifstream stream(filename.c_str(), std::ios::binary);SHA1 checksum;checksum.update(stream);return checksum.final();
}#endif /* SHA1_HPP */

dic.h

#include "Chord_sha1.h"
#include "sha1.hpp"
using namespace std;static int MaxNum = 100;// 使用字符分割
void Stringsplit(const string& str, const char split, vector<string>& res)
{// int i = 0;if (str == ""){return;}//在字符串末尾也加入分隔符,方便截取最后一段string strs = str + split;size_t pos = strs.find(split);// 若找不到内容则字符串搜索函数返回 nposwhile (pos != strs.npos){string temp = strs.substr(0, pos);res.push_back(temp);//去掉已分割的字符串,在剩下的字符串中进行分割strs = strs.substr(pos + 1, strs.size());pos = strs.find(split);}
}int Charge(Node *n0) {SHA1 sha1;ifstream srcFile("dic.txt", ios::in); //以文本模式打开dic.txt备读if (!srcFile) { //打开失败cout << "文件读取失败" << endl;return -1;}cout << "文件打开成功" << endl;int n;for(n = 1; n < MaxNum; n++) {sha1.update(to_string(n));Node *node = new Node(sha1.final());node->Join(n0);}Node *t = n0;int i = 0;for(i = 0; i < MaxNum; i++) {t->stabilize();t = t->fingertable->fingerTable[0];}cout << "结点加入成功" << endl;//存储string s1;vector<string> s2;while(getline(srcFile, s1, '\n')) {Stringsplit(s1, ' ', s2);sha1.update(s2[0]);string s = sha1.final();n0->Insert(s, s2[2]);// cout << s2[0] << endl;s2.clear();}return 0;
}

CPP文件:

展示用:Chord.cpp

#include "Chord_sha1.h"
#include "sha1.hpp"int StopFun() {int i;while(1) {std::cout << "是否要退出?(1.退出/0.返回)" << std::endl;std::cin >> i;if(i == 1) {return 1;}else if(i == 0) {return 0;}else {std::cout << "输入错误!" << std::endl;}}
}int main() {int index;int TotalNum = 1;bool tag = true;SHA1 sha1;// n0 joinNode* n0 = new Node("0");  n0->Join(NULL);cout << "N0(0)结点初始化完成" << endl;while(tag) {system("CLS");cout << "********************************" << endl;cout << "*       1.插入Insert           *" << endl;cout << "*       2.查询Lookup           *" << endl;cout << "*       3.加入新结点Join       *" << endl;cout << "*       4.退出结点Leave        *" << endl;cout << "*       5.更新结点Update       *" << endl;cout << "*       6.打印结点信息         *" << endl;cout << "*      -1.退出                 *" << endl;cout << "********************************" << endl;cout << "请输入序号:" << endl;cin >> index;switch (index){case 1:system("CLS");{cout << "输入插入数据的key:" << endl;string key;cin >> key;sha1.update(key);cout << "输入插入数据的信息:" << endl;string value;cin >> value;n0->Insert(sha1.final(), value);cout << "信息已插入" << endl;}system("pause");break;case 2:system("CLS");{cout << "输入查询数据的key:" << endl;string key;cin >> key;sha1.update(key);string s = sha1.final();cout << "对应Sha-1散列值为:" << s << endl;cout << n0->LookUp(s) << endl;}system("pause");break;case 3:system("CLS");{cout << "输入加入结点序号:" << endl;int n;cin >> n;sha1.update(to_string(n));string s = sha1.final();Node *node = new Node(s);node->Join(n0);// node->fingertable->printFingerTable();// node->stabilize();// node->fingertable->printFingerTable();cout << "新结点已加入" << endl;cout << "对应Sha-1散列值为:" << s << endl;TotalNum++;}system("pause");break;case 4:system("CLS");{cout << "输入退出结点序号:" << endl;int n;cin >> n;sha1.update(to_string(n));string s = sha1.final();n0->Leave(s);cout << "结点已退出" << endl;TotalNum--;}system("pause");break;case 5:system("CLS");{Node *t = n0;int i = 0;for(i = 0; i < TotalNum; i++) {t->stabilize();t = t->fingertable->fingerTable[0];}}system("pause");break;case 6:system("CLS");{Node *t = n0;int i = 0;for(i = 0; i < TotalNum; i++) {t->fingertable->printFingerTable();t = t->fingertable->fingerTable[0];}}system("pause");break;case -1:system("CLS");{int x = StopFun();if(x == 1) {tag = false;break;}else {break;                }}default:cout << "请选择正确序号!" << endl;system("pause");break;}}system("pause");return 0;
}

英文词典:Dictionary.cpp

#include <bits/stdc++.h>
#include "dic.h"
using namespace std;int StopFun() {int i;while(1) {std::cout << "是否要退出?(1.退出/0.返回)" << std::endl;std::cin >> i;if(i == 1) {return 1;}else if(i == 0) {return 0;}else {std::cout << "输入错误!" << std::endl;}}
}int main() {int TotalNum = 100;int index;bool tag = true;SHA1 sha1;// n0 joinNode* n0 = new Node("0");    n0->Join(NULL);cout << "N0(0)结点初始化完成" << endl;int n = Charge(n0);if(n == -1) {return 0;}system("pause");while(tag) {system("CLS");cout << "*************************" << endl;cout << "*       1.搜索          *" << endl;cout << "*       2.打印结点      *" << endl;cout << "*      -1.退出          *" << endl;cout << "**************************" << endl;cout << "请输入序号:" << endl;cin >> index;switch (index){case 1:system("CLS");{string s;cout << "输入查询的单词:" << endl;cin >> s;sha1.update(s);cout << n0->LookUp(sha1.final()) << endl;}system("pause");break;case 2:system("CLS");{Node *t = n0;int i = 0;for(i = 0; i < TotalNum; i++) {cout << i + 1 << endl;t->fingertable->printFingerTableWithoutKey();t = t->fingertable->fingerTable[0];}}system("pause");break;case -1:system("CLS");{int x = StopFun();if(x == 1) {tag = false;break;}else {break;                }}   default:cout << "请选择正确序号!" << endl;system("pause");break;}}return 0;
}

词典文件:

链接:/s/12UapWwi2-jVDneO6HSrAtg 
提取码:hell

可能仍有BUG

未实现VC可视化与验证实验结果

带注释_合工大数据结构课设Chord网络的模拟(90分)相关推荐

  1. 数据结构课设_网页形式的景区导游

    一.前言 欢迎大家来到这里~~ 1.这次数据结构课设,笔者的题目是网页形式的导航系统. 2.数据结构方面应用了链表存储商品信息.图来存储景点和路径信息.在图的广度优先中还用到了队列: 3.具体的算法有 ...

  2. 一元稀疏多项式计算器 【 数据结构课设作业 】 带界面,无bug,可以直接运行

    一元稀疏多项式计算器 问题描述 设计一个一元稀疏多项式简单计算器. 基本要求 (1)输入并建立多项式. (2)输出多项式,输出形式为整数序列:n,c1,e1,c2,e2,-,cn,en,其中n是多项式 ...

  3. 数据结构课设+校园导航系统+西安邮电大学

    数据结构课设+校园导航系统+西安邮电大学 设计目的:在校园建设不断完善的现在,为在校学生提供合适的行走路径,为来访的客人提供各种服务的信息:对于这些问题,可用图结构来表示校园交通网络,编写程序完成校园 ...

  4. 南京航空航天大学2020数据结构课设

    南京航空航天大学2020数据结构课设 目录 1.系统进程设计 2.迷宫问题 3.家谱管理系统 4.Huffman编码与解码 5.地铁修建 6.公交线路提示 7.B-树应用 8.排序算法比较 9.数字排 ...

  5. 地大c语言课程设计题目,中国地质大学数据结构课设-全国铁路运输网最佳经由问题课程设计报告精选.doc...

    中国地质大学数据结构课设-全国铁路运输网最佳经由问题课程设计报告精选 数据结构 上机实习报告 实验题目:全国铁路运输网最佳经由问题 班级: 姓名: 学号: 完成日期:2017年4月25日 目录 课程设 ...

  6. 那些年,我的数据结构课设,现在满满的回忆!(现如今身处内卷之中,已经很难出现当初那份乐趣了)

    一.看到这个图标很有感觉 距离当初完成数据结构课设已经过去很久很久了,当初由于U盘失踪,也丢失了很多宝贵的东西,我也伤心的好久`(>﹏<)′!不过最近找到了失散多年的亲兄弟,打开U盘,感概 ...

  7. 学生搭配问题数据结构报告c语言,数据结构课设学生搭配问题

    数据结构课设学生搭配问题 数 据 结 构 课程设计报告书 班级 学号 专业 姓名 课题描述: 一. 需求分析: 1. 设计内容 一班有m个女生,有n个男生(m不等于n),现要开一个舞会. 男女生分别编 ...

  8. 神秘国度的爱情故事 数据结构课设-广州大学

    神秘国度的爱情故事 数据结构课设-广州大学 ps:本次课设程序不仅需要解决问题,更需要注重代码和算法的优化和数据测试分析      直接广度优先实现的方法时间复杂度为O(QN),优化后的方法是lca+ ...

  9. 模拟浏览器操作程序(数据结构课设)

    文章目录 前言 一.题目 二.系统设计 2.1 功能模块图 2.2 主要功能函数 三.问题分析 四.实验结果及分析 五.源码 总结 前言 20级cqut的别抄! 一.题目  模拟浏览器操作程序:标准的 ...

最新文章

  1. python并发编程:阻塞IO
  2. 实战项目 10: 货物清单应用
  3. Visual Studio Code设置断点时出现Unverified breakpoint该咋办
  4. 业务的可变性和不可变性分析_不可变性真的意味着线程安全吗?
  5. js删除mysql记录_(DELETEUPDATE)修改、删除数据记录_MySQL
  6. 实例60:python
  7. php添加填空,PHP之preg_replace_callback(),将填空题的[[]]替换成______
  8. 大数据Hadoop之——Cloudera Hadoop(CM 6.3.1+CDH 6.3.2环境部署)
  9. xxl-job定时任务
  10. Docker提交天池比赛流程
  11. N76E003 串口ISP如何使用
  12. vulhub漏洞复现-bash(CVE-2014-6271) shellshock-破壳漏洞
  13. 记录盈透IBKR IBAPI Quant过程
  14. 程序人生丨想学编程,大学什么样的专业能成为一名真正的程序员?
  15. 深入理解Android EventBus原理
  16. Nat. Methods | 基于机器学习和生物物理的蛋白质-肽相互作用预测
  17. Matlab数据分析与计算,进程线程面试题总结
  18. 商业级web阅读器项目(上)
  19. 新东方国际教育为多人群提供留学语培解决方案
  20. Android利用AccessibilityService实现自动装总结(一)

热门文章

  1. 基于共现关系的人物关系图
  2. android自定义本地邮箱联想组件(基于MultiAutoCompleteTextView)
  3. 实体型转换为一个关系模式
  4. IBM测试分类-AVT,BVT,CVT,FVT,GVT,TVT,SVT,PVT
  5. C语言 | 学习使用递增运算符
  6. talend导出数据到oracle,Talend使用步骤.pdf
  7. php怎么添加背景图html,html怎么导入背景图
  8. 苹果电脑打开任何来源
  9. Web前端最新优化指标:FP、FCP、FMP、LCP、TTI、CLS、FID、FPS等
  10. Cisco DHCP Snooping