From af86e1f787faa9af9e70bb05c158a8be76ab9f61 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 29 Apr 2014 17:06:03 +0800 Subject: [PATCH] dsdv --- Makefile | 11 ++ README.md | 44 +++++++ README~ | 46 +++++++ a.dat | 4 + a.dat~ | 4 + b.dat | 4 + b.dat~ | 4 + c.dat | 6 + d.dat | 5 + dsdv | Bin 0 -> 71079 bytes dsdv.cpp | 144 ++++++++++++++++++++++ e.dat | 4 + f.dat | 3 + make | 1 + rip.cpp | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++ rip.h | 50 ++++++++ socket.cpp | 98 +++++++++++++++ socket.h | 17 +++ 18 files changed, 796 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 README~ create mode 100644 a.dat create mode 100644 a.dat~ create mode 100644 b.dat create mode 100644 b.dat~ create mode 100644 c.dat create mode 100644 d.dat create mode 100755 dsdv create mode 100644 dsdv.cpp create mode 100644 e.dat create mode 100644 f.dat create mode 100644 make create mode 100644 rip.cpp create mode 100644 rip.h create mode 100644 socket.cpp create mode 100644 socket.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..de476b2 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +# NOTE: Feel free to change the makefile to suit your own need. + +# compile and link flags +CC=g++ + +all: + g++ -std=c++0x -pthread dsdv.cpp rip.cpp socket.cpp -o dsdv + + +clean: + rm -f *~ *.o dsdv diff --git a/README.md b/README.md new file mode 100644 index 0000000..aadb2ff --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ + + +文件构成: + 本次lab主要由5个文件构成 + socket.h & socket.cpp用来提供udp socket方面的接口和实现,具体内容可以参考socket.h + + rip.h & rip.cpp用来提供路由算法的接口和实现,主要包含两个struct和6个函数接口 + + struct RouterTab:用来保存路由表中每一行的数据,其中seqNum表示重点的seqNum + struct Host:用来表示主机,包括主机的名称,seqNum和路由表的行数 + + void ripInit(string filename, map &table, map &adjTab, struct Host &host) + 用来初始化路由器,从filename中读入表项并将其保存到table中,将端口号和名称的映射保存在adjTab中,将host信息保存到host中 + void ripSend(string &content, map &table, struct Host &host) + 用来住准备发送内容,将主机信息和路由表转换成string保存到content中 + void ripUpdate(struct Host from, map &srcTab, map &adjTable, map &routeTable, struct Host &host) + 当收到邻节点from的路由表srcTab是,根据主机保存的信息更新 + void ripRefresh(map &bufferdAdj, map &newAdj, map &table, struct Host &host) + 根据重新从磁盘读入的newAdj和之前保存的bufferAdj来更新host的信息 + void ripReceive(string content, map &srcTab, struct Host &from); + 将收到邻节点的content信息转换成srcTab的路由表和from的路由器信息 + void ripPrintTable(map &table, int &printNum, struct Host &host) + 打印主机信息 + + + dsdv.cpp + 模拟路由器本身,采用双线程的方式,一个线程用来监听udp端口,接受并且更新路由表。另一个线程用来定时刷新路由表并且发送。详细参见dsdv.cpp + +路由表查找及更新的算法 + 采用了dsdv的基本思路,通过seqNum来表示路由的最新状态。路径中的seqNum代表末节点的seqNum,其中如果seqNum是奇数,表示路由器正处在中间状态,他不能被更新,也不能更新其他路由器 + 1.从硬盘刷新路由表:从硬盘读取新数据,比对路由器缓存的旧表(adjBuf),如果有变动,将自己的seqNum ++,同时将所有的到邻节点的路全部强制刷新成直接链接。并且更新路由表中所有通过邻节点的路径的cost。 + 2.从邻节点更新路由表:首先存在4中情况:1.from seqNum 为偶数,host 为偶数;2.from 偶数,host奇数;3.from 奇数,host 奇数;4.from 奇数, host 偶数; + 对于1.from为中间状态,忽略 + 2.host处于中间状态,忽略 + 3.表示from和host正好是更新的边的两端点,更新到对应路径的seqNum,并且自身的seqNum ++ + 4.又可以分为两种子情况,如果from的路由表中到自己的路线的seqNum为奇数,更行他的seqNum,此时中间状态完全结束,否则进行正常更新步骤 + 由于硬盘刷新策略的设计是全部换成直连,所以当host路由表中发现from的seqNum大于路由表中保存的信息时,从buffer的邻节点表中更新所有到邻节点的路径。并且对路由表的路径也进行重新计算 + 如果发现相等,对于所有路径进行更新:如果from中终点的seqNum较大,强制更新。否则重新计算路径的cost,以及判断是否改变路由路线从而获取最优值 + + 对于这个算法,只要有路线变化,他们的影响就会从变化的两个端点扩散出去,最差的情况可能就是整张路由表全部直间连接(相当与重建),然后逐步优化到最优,虽然效率一般,但是实现比较方便。 + + + + diff --git a/README~ b/README~ new file mode 100644 index 0000000..200df01 --- /dev/null +++ b/README~ @@ -0,0 +1,46 @@ +ID: 5110379042 +Name: 付周望 +E-mail: frankfzw@sjtu.edu.cn + +文件构成: + 本次lab主要由5个文件构成 + socket.h & socket.cpp用来提供udp socket方面的接口和实现,具体内容可以参考socket.h + + rip.h & rip.cpp用来提供路由算法的接口和实现,主要包含两个struct和6个函数接口 + + struct RouterTab:用来保存路由表中每一行的数据,其中seqNum表示重点的seqNum + struct Host:用来表示主机,包括主机的名称,seqNum和路由表的行数 + + void ripInit(string filename, map &table, map &adjTab, struct Host &host) + 用来初始化路由器,从filename中读入表项并将其保存到table中,将端口号和名称的映射保存在adjTab中,将host信息保存到host中 + void ripSend(string &content, map &table, struct Host &host) + 用来住准备发送内容,将主机信息和路由表转换成string保存到content中 + void ripUpdate(struct Host from, map &srcTab, map &adjTable, map &routeTable, struct Host &host) + 当收到邻节点from的路由表srcTab是,根据主机保存的信息更新 + void ripRefresh(map &bufferdAdj, map &newAdj, map &table, struct Host &host) + 根据重新从磁盘读入的newAdj和之前保存的bufferAdj来更新host的信息 + void ripReceive(string content, map &srcTab, struct Host &from); + 将收到邻节点的content信息转换成srcTab的路由表和from的路由器信息 + void ripPrintTable(map &table, int &printNum, struct Host &host) + 打印主机信息 + + + dsdv.cpp + 模拟路由器本身,采用双线程的方式,一个线程用来监听udp端口,接受并且更新路由表。另一个线程用来定时刷新路由表并且发送。详细参见dsdv.cpp + +路由表查找及更新的算法 + 采用了dsdv的基本思路,通过seqNum来表示路由的最新状态。路径中的seqNum代表末节点的seqNum,其中如果seqNum是奇数,表示路由器正处在中间状态,他不能被更新,也不能更新其他路由器 + 1.从硬盘刷新路由表:从硬盘读取新数据,比对路由器缓存的旧表(adjBuf),如果有变动,将自己的seqNum ++,同时将所有的到邻节点的路全部强制刷新成直接链接。并且更新路由表中所有通过邻节点的路径的cost。 + 2.从邻节点更新路由表:首先存在4中情况:1.from seqNum 为偶数,host 为偶数;2.from 偶数,host奇数;3.from 奇数,host 奇数;4.from 奇数, host 偶数; + 对于1.from为中间状态,忽略 + 2.host处于中间状态,忽略 + 3.表示from和host正好是更新的边的两端点,更新到对应路径的seqNum,并且自身的seqNum ++ + 4.又可以分为两种子情况,如果from的路由表中到自己的路线的seqNum为奇数,更行他的seqNum,此时中间状态完全结束,否则进行正常更新步骤 + 由于硬盘刷新策略的设计是全部换成直连,所以当host路由表中发现from的seqNum大于路由表中保存的信息时,从buffer的邻节点表中更新所有到邻节点的路径。并且对路由表的路径也进行重新计算 + 如果发现相等,对于所有路径进行更新:如果from中终点的seqNum较大,强制更新。否则重新计算路径的cost,以及判断是否改变路由路线从而获取最优值 + + 对于这个算法,只要有路线变化,他们的影响就会从变化的两个端点扩散出去,最差的情况可能就是整张路由表全部直间连接(相当与重建),然后逐步优化到最优,虽然效率一般,但是实现比较方便。 + + + + diff --git a/a.dat b/a.dat new file mode 100644 index 0000000..481d51a --- /dev/null +++ b/a.dat @@ -0,0 +1,4 @@ +3 a +b -2.0 3032 +c 5.0 3033 +d 1.0 3034 diff --git a/a.dat~ b/a.dat~ new file mode 100644 index 0000000..82c56de --- /dev/null +++ b/a.dat~ @@ -0,0 +1,4 @@ +3 a +b 2.0 3032 +c 5.0 3033 +d 1.0 3034 diff --git a/b.dat b/b.dat new file mode 100644 index 0000000..f807cfb --- /dev/null +++ b/b.dat @@ -0,0 +1,4 @@ +3 b +a -2.0 3031 +c 3.0 3033 +d 2.0 3034 diff --git a/b.dat~ b/b.dat~ new file mode 100644 index 0000000..4231b2d --- /dev/null +++ b/b.dat~ @@ -0,0 +1,4 @@ +3 b +a 2.0 3031 +c 3.0 3033 +d 2.0 3034 diff --git a/c.dat b/c.dat new file mode 100644 index 0000000..a5125f1 --- /dev/null +++ b/c.dat @@ -0,0 +1,6 @@ +5 c +b 3.0 3032 +d 3.0 3034 +a 5.0 3031 +e 1.0 3035 +f 5.0 3036 diff --git a/d.dat b/d.dat new file mode 100644 index 0000000..044e5ec --- /dev/null +++ b/d.dat @@ -0,0 +1,5 @@ +4 d +c 3.0 3033 +e 1.0 3035 +a 1.0 3031 +b 2.0 3032 diff --git a/dsdv b/dsdv new file mode 100755 index 0000000000000000000000000000000000000000..c0186c91d61677a4f5499b55a2796e11c3b4c17f GIT binary patch literal 71079 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 HR5ky9ldnS3 literal 0 HcmV?d00001 diff --git a/dsdv.cpp b/dsdv.cpp new file mode 100644 index 0000000..8c759c5 --- /dev/null +++ b/dsdv.cpp @@ -0,0 +1,144 @@ +#include "rip.h" +#include "socket.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +mutex mtx; + +//global variable + +//store the table from disk temporarily +map myTable; + +//store adjacent nods map +map adjBuf; + +//store the route table +map routerTable; + +//store the map from port number to the name of router +map portToName; + +//store the host message +struct Host host; + +//store the socket fd +int fd; + +//store the print time +int printNum; + + +void* receive(void* ptr) +{ + //cout<<"thread 1\n"; + + while(1) + { + string content; + int fromPort = socketReceive(fd, content); + //cout<<"receive from: "<second; + Host srcRouter; + srcRouter.name = src; + map srcTab; + + //cout<<"========================\n"; + //cout<<"receive from: "< \n", argv[0]); + exit(-1); + } + + int port = atoi(argv[1]); + if(port <= 0) + { + printf("error: invalid \n"); + exit(-1); + } + + string filename = string(argv[2]); + + try + { + //init + + ripInit(filename, routerTable, portToName, host); + ripInit(filename, adjBuf, portToName, host); + cout<<"This is router "<::iterator it = portToName.begin(); + for(; it != portToName.end(); it ++) + { + socketSend(fd, it->first, sendContent); + } + + sleep(1); + } + close(fd); + } + catch(int e) + { + cout<<"Oops! error code: "< +#include +#include "rip.h" +#include +#include +#include +#include + + +using namespace std; + +void ripInit(string filename, map &table, map &adjTab, struct Host &host) +{ + //clear data + //table.clear(); + host.seqNum = 0; + host.vectorNum = 0; + ifstream ifs; + ifs.open(filename.c_str(), ifstream::in); + + if(!ifs.good()) + { + ifs.close(); + throw NOT_FOUND; + } + + int lineNum = 0; + string name; + ifs>>lineNum>>name; + host.name = name; + /*RouterTab self; + self.dst = name; + self.cost = 0; + self.hop = name; + self.seqNum = 0; + table[name] = self;*/ + + while(lineNum--) + { + if(ifs.eof()) + { + ifs.close(); + throw FILE_ERR; + } + + string dst = ""; + double cost = 0; + int portNum = 0; + ifs>>dst>>cost>>portNum; + + RouterTab tab = {}; + tab.dst = dst; + if(cost < 0) + cost = MAX; + tab.cost = cost; + tab.hop = dst; + tab.seqNum = 0; + table[dst] = tab; + host.vectorNum ++; + + map::iterator it; + //if((it = adjTab.find(portNum)) == adjTab.end()) + adjTab[portNum] = dst; + + } + + ifs.close(); +} + + +void ripSend(string &dst, map &table, struct Host &host) +{ + ostringstream oss; + oss<::iterator it = table.begin(); + //int length = 0; + for(;it != table.end(); it ++) + { + oss<<(it->second).dst<<' '<<(it->second).cost<<' '<<(it->second).hop<<' '<<(it->second).seqNum<<'\n'; + //length ++; + } + + //the head of the content is the number of router vectors + //ostringstream temp; + //temp< &srcTab, map &adjTable, map &routeTable, struct Host &host) +{ + //host is in the intermidate status + if(((from.seqNum % 2) == 0) && ((host.seqNum % 2) == 1)) + { + //routh changing successed + + if((srcTab.find(host.name)->second).seqNum == host.seqNum) + { + host.seqNum ++; + (routeTable.find(from.name)->second).seqNum = from.seqNum; + } + + return; + } + + //from is in the intermidate status + if(((from.seqNum % 2) == 1) && ((host.seqNum % 2) == 0)) + { + return; + } + + //from is the exactly one + if(((from.seqNum % 2) == 1) && ((host.seqNum % 2) == 1)) + { + host.seqNum ++; + (routeTable.find(from.name))->second.seqNum = from.seqNum; + return; + } + + //finish the intermidate status + if((routeTable.find(from.name)->second).seqNum % 2) + { + (routeTable.find(from.name)->second.seqNum) = from.seqNum; + return; + } + + //1st: if from is a new one, change the route to directly + if(from.seqNum > (routeTable.find(from.name)->second).seqNum) + { + (routeTable.find(from.name)->second).seqNum = from.seqNum; + //change all route to adj directly + map::iterator it = adjTable.begin(); + + for(; it != adjTable.end(); it ++) + { + string name = (it->second).dst; + double oldCost = (routeTable.find(name)->second).cost; + double newCost = (it->second).cost; + (routeTable.find(name)->second).cost = newCost; + (routeTable.find(name)->second).hop = name; + map::iterator itt = routeTable.begin(); + for(; itt != routeTable.end(); itt ++) + { + if(name.compare((itt->second).dst) == 0) + continue; + if(name.compare((itt->second).hop) != 0) + continue; + + //cout<<"eeeeeee\t"<second.cost<<'\t'<second).cost += newCost - oldCost; + + + if((itt->second).cost > MAX) + (itt->second).cost = MAX; + } + + } + } + else if(from.seqNum == (routeTable.find(from.name)->second).seqNum) + { + //adj node didn't finish 1st step + if((srcTab.find(host.name)->second).seqNum < host.seqNum) + return; + + map::iterator it; + map::iterator it2; + double fromCost = (routeTable.find(from.name)->second).cost; + for(it2 = srcTab.begin(); it2 != srcTab.end(); it2 ++) + { + string name = (it2->second).dst; + string hop = (it2->second).hop; + it = routeTable.find(name); + + + //route back to host + if(name.compare(host.name) == 0) + continue; + + //it's a new route + if(it == routeTable.end()) + { + RouterTab temp; + temp.dst = name; + temp.hop = from.name; + double newCost = fromCost + (it2->second).cost; + newCost = (newCost > MAX) ? MAX : newCost; + temp.cost = newCost; + + //cout<<"aaaaaaa\t"<second).seqNum; + routeTable[name] = temp; + host.vectorNum ++; + } + + //the route is existed + else + { + //ignore the route which pass by it self + if(hop.compare(host.name) == 0) + continue; + + //ignore the old route path + if((it2->second).seqNum < (it->second).seqNum) + continue; + + //froce updating + else if((it2->second).seqNum > (it->second).seqNum) + { + double newCost = fromCost + (it2->second).cost; + newCost = (newCost > MAX) ? MAX : newCost; + (it->second).cost = newCost; + + //cout<<"bbbbbbb\t"<second).seqNum = (it2->second).seqNum; + (it->second).hop = from.name; + } + else + { + //update route cost and seqNum + double newCost = fromCost + (it2->second).cost; + newCost = (newCost > MAX) ? MAX : newCost; + + //cout<<"ccccccc\t"<second).cost<second).hop).compare(from.name) == 0) + { + (it->second).cost = newCost; + //return; + } + + //new path is better + if(newCost < (it->second).cost) + { + (it->second).cost = newCost; + + //check if host to from route directly + string hopHtoF = (routeTable.find(from.name)->second).hop; + if(hopHtoF.compare(from.name) == 0) + { + (it->second).hop = from.name; + } + else + (it->second).hop = hopHtoF; + //cout<<"here!!!!!!!\nfrom:\t"<second.dst<<'\t'<second.hop<second).seqNum = srcTab[i].seqNum; + } + + } + } + } + } + + +} + +void ripRefresh(map &bufferdAdj, map &newAdj, map &table, struct Host &host) +{ + string name; + double newCost; + double oldCost; + + map::iterator it = bufferdAdj.begin(); + for(; it != bufferdAdj.end(); it ++) + { + double cost = (it->second).cost; + name = (it->second).dst; + newCost = (newAdj.find(name)->second).cost; + if(abs(cost - newCost) < 0.000001) + continue; + else + { + //table.clear(); + //table = newAdj; + //host.seqNum ++; + break; + } + } + + //table didn't change + if(it == bufferdAdj.end()) + return; + + + //change all route to adj directly + for(it = newAdj.begin(); it != newAdj.end(); it ++) + { + name = (it->second).dst; + newCost = (it->second).cost; + oldCost = (table.find(name)->second).cost; + (table.find(name)->second).cost = newCost; + (table.find(name)->second).hop = name; + map::iterator itt = table.begin(); + for(; itt != table.end(); itt ++) + { + if(name.compare((itt->second).dst) == 0) + continue; + if(name.compare((itt->second).hop) != 0) + continue; + (itt->second).cost += newCost - oldCost; + + //cout<<"ddddddd\t"<<(itt->second).cost<second).cost > MAX) + (itt->second).cost = MAX; + + + + } + + } + bufferdAdj = newAdj; + host.seqNum ++; +} + +void ripReceive(string content, map &srcTab, struct Host &from) +{ + istringstream iss(content); + + iss>>from.vectorNum>>from.seqNum; + int length = from.vectorNum; + + while(length --) + { + RouterTab temp; + iss>>temp.dst>>temp.cost>>temp.hop>>temp.seqNum; + srcTab[temp.dst] = temp; + } +} + +void ripPrintTable(map &table, int &printNum, struct Host &host) +{ + printNum ++; + cout<<"##print-out number\t"<::iterator it = table.begin(); + for(; it != table.end(); it ++) + { + string dst = (it->first); + string hop = (it->second).hop; + int seqNum = (it->second).seqNum; + double cost = (it->second).cost; + cout<<"shortest path to node "< "< +#include +#include + +using namespace std; + +#define NOT_FOUND 0 +#define FILE_ERR 1 +#define DATA_ERR 2 +#define DATA_UNMATCH 3 +#define MAX 10000 + +struct RouterTab{ + string dst; + string hop; + int seqNum; + double cost; +}; + +struct Host{ + string name; + int seqNum; + int vectorNum; +}; + + + +/*read the data from disk file and get the name of router*/ +void ripInit(string filename, map &table, map &adjTab, struct Host &host); + +/*convert the router table to string*/ +void ripSend(string &content, map &table, struct Host &host); + +/*receive the router table from src router and update own table*/ +void ripUpdate(struct Host from, map &srcTab, map &adjTable, map &routeTable, struct Host &host); + +/*refresh the route table*/ +void ripRefresh(map &bufferdAdj, map &newAdj, map &table, struct Host &host); + +/*receive the socket content and turn it to map*/ +void ripReceive(string content, map &srcTab, struct Host &from); + +/*print router table*/ +void ripPrintTable(map &table, int &printNum, struct Host &host); + + +#endif diff --git a/socket.cpp b/socket.cpp new file mode 100644 index 0000000..c03e366 --- /dev/null +++ b/socket.cpp @@ -0,0 +1,98 @@ +#include "socket.h" +#include +#include +#include +#include +#include + + +using namespace std; + +int socketBind(int port) +{ + //create socket + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if(fd == -1) + { + perror("creat error\n"); + return -1; + } + + //printf("create socket, fd: %d\n", fd); + + //build connection + struct sockaddr_in siMe; + memset((char *) &siMe, 0, sizeof(siMe)); + + siMe.sin_family = AF_INET; + siMe.sin_port = htons(port); + siMe.sin_addr.s_addr = inet_addr("127.0.0.1"); + + int r = bind(fd, (struct sockaddr*)&siMe, sizeof(siMe)); + if(r == -1) + { + perror("bind error\n"); + close(fd); + return -1; + } + //printf("bind successfully!\n"); + return fd; + +} + +int socketSend(int fd, int port, string content) +{ + //build buffer + + char *buf = new char[BUFFERSIZE]; + memset(buf, '\0', BUFFERSIZE); + strcpy(buf, content.c_str()); + + //build connection + struct sockaddr_in siTo; + memset((char *) &siTo, 0, sizeof(siTo)); + + siTo.sin_family = AF_INET; + siTo.sin_port = htons(port); + siTo.sin_addr.s_addr = inet_addr("127.0.0.1"); + + + //printf("socketSend %s\n", buf); + + //send content + int r = sendto(fd, buf, BUFFERSIZE - 1, 0, (struct sockaddr*)&siTo, sizeof(siTo)); + if(r == -1) + { + perror("send error\n"); + return -1; + } + return 0; +} + +int socketReceive(int fd, string &content) +{ + char *buf = new char[BUFFERSIZE]; + memset(buf, '\0', BUFFERSIZE); + + //build connection + struct sockaddr_in siFrom; + memset((char *)&siFrom, 0, sizeof(siFrom)); + + //receive content + socklen_t len = sizeof(siFrom); + int r = recvfrom(fd, buf, BUFFERSIZE - 1, 0, (struct sockaddr *)&siFrom, &len); + + if(r > 0) + { + int port = ntohs(siFrom.sin_port); + + //read buffer + content = string(buf); + return port; + } + //perror("receive error\n"); + return -1; + + + +} diff --git a/socket.h b/socket.h new file mode 100644 index 0000000..7e7299d --- /dev/null +++ b/socket.h @@ -0,0 +1,17 @@ +#ifndef _SOCKET_H_ +#define _SOCKET_H_ + +#include + +#define BUFFERSIZE 2048 + +/*bind socket return fd if success*/ +int socketBind(int port); + +/*send content to the router on port, return 0 if success*/ +int socketSend(int fd, int port, std::string content); + +/*receive content, return port number if success, else return -1*/ +int socketReceive(int fd, std::string &content); + +#endif