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 0000000..c0186c9 Binary files /dev/null and b/dsdv differ 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