我正在cpp中实现距离矢量路由协议。当我将路由表信息作为字符串发送到buffer
时,它没有收到它,而是显示了垃圾值。 buffer
正在从clk
接收driver.py
。客户端python代码也没有问题。
Router.cpp
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <set>
#include <iostream>
#include <fstream>
#include <string>
#include <bits/stdc++.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <map>
using namespace std;
const int INF = 99999;
int sendClock = 0;
bool entryChanged = false;
//socket programming variables
int sockfd,bind_flag,bytes_received;
socklen_t addrlen;
class routingTableEntry
{
public:
string nextHop;
int cost;
routingTableEntry(){};
routingTableEntry(string nextHop, int cost){ this->nextHop = nextHop; this->cost = cost;};
};
//operator overload
ostream &operator <<(std::ostream &os, const routingTableEntry& row)
{
if(row.nextHop == "-") os << " " << row.nextHop << "\t";
else os << row.nextHop << "\t\t";
if(row.cost == INF) os << "\t\tINF";
else os << row.cost;
return os;
}
map<string,routingTableEntry> routingTable;//destination is key,(nextHop,cost) value
vector<string> neighbors; //needed in sendTable and initRouter
set<string> routerSet; //contains all the routers/ip
//performs initial insertion of info in routing table
//by reading from topo.txt file
void initRouter(string routerIP, string topologyFile);
routingTableEntry getRouteEntry(string row, string delim);
void printRoutingTable(string ip);
void printMap();
void initRouter(string routerIP, string topologyFile)
{
ifstream topo(topologyFile);
string r1, r2;
int cost;
string line;
while(getline(topo, line))
{
istringstream iss(line);
while(iss>>r1>>r2>>cost){
if(!r1.compare(routerIP))
{
//if r2 is neighbor of r1 insert it to vector neighbor
//if not already inserted
neighbors.push_back(r2);
routingTableEntry rte (r2,cost);
if(routingTable.find(r2) == routingTable.end()){
routingTable.insert(make_pair(r2,rte));
}
}
else if(!r2.compare(routerIP))
{
neighbors.push_back(r1);
routingTableEntry rte (r1,cost);
if(routingTable.find(r1) == routingTable.end()){
routingTable.insert(make_pair(r1,rte));
}
}
routerSet.insert(r1);
routerSet.insert(r2);
}
}
//topo.close();
cout<<"~~~~~~printing neighbors in initRouter~~~~~~~~~~~`"<<endl;
for(int i = 0 ; i < (int) neighbors.size() ; i++){
cout << neighbors[i] << "\n";
}
auto itr = routerSet.begin();
while(itr != routerSet.end()){
string ip = *itr;
//if(`ip == routerIP) { itr++; continue; }
if(ip == routerIP) {
routingTableEntry rte(ip,0);
routingTable.insert(make_pair(ip,rte));
}
if(routingTable.find(ip) == routingTable.end()){
routingTableEntry rt;
rt.nextHop = "-";
rt.cost = INF;
routingTable.insert(make_pair(ip,rt));
}
itr++;
}
printMap();
}
//takes as parameter routing table info for node n,
//which has beenconverted to string in makeTableIntoPacket
//returns a vector routing table, and not a map
vector<routingTableEntry> extractTableFromPacket(string packet)
{
vector<routingTableEntry> rt;
char *str = new char[packet.length()+1];
strcpy(str, packet.c_str());
char *token = strtok(str,":");
vector<string> entries;
while(token != NULL)
{
entries.push_back(token);
token = strtok(NULL,":");
}
routingTableEntry rte;
for(int i = 0; i<entries.size(); i++)
{
rte = getRouteEntry(entries[i],"#");
rt.push_back(rte);
cout<<" next : "<<rte.nextHop<<" cost : "<<rte.cost<<endl;
}
return rt;
}
//converts routing table info in string
//returns this string which is extracted in extractTablefromPacket
string makeTableIntoPacket(string routerIP)
{
cout<<"~~~~~~~~~in makeTableIntoPacket ~~~~~~~~~~~~"<<endl;
string routingTablePacket;
auto it = routerSet.begin();
while(it != routerSet.end()){
string ip = *it;
if(ip == routerIP) { it++; continue; }
auto result = routingTable.find(ip);
routingTableEntry row = result-> second;
routingTablePacket += ip + "#" + row.nextHop + "#" + std::to_string(row.cost) ;
it++;
}
cout<<routingTablePacket<<endl;
return routingTablePacket;
}
//sends routing tableinfo to neigboring nodes
void sendTable(string routerIP)
{
cout<<"in send table"<<endl;
//printMap();
//here i used ":" as the header by which the buffer will identify the incoming packet
string tablePacket = ":"+makeTableIntoPacket(routerIP);
cout<<"tablePacket is "<<tablePacket<<endl;
//string routingTablePacket = "Routing table from neighbor " + routerIP + "\n" + makeTableIntoPacket(routerIP);
for(int i = 0; i < (int) neighbors.size(); i++)
{
//cout<<"in for"<<endl;
/*struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(4747);
server_address.sin_addr.s_addr = inet_addr(neighbors[i].c_str());
client_address.sin_family = AF_INET;
client_address.sin_port = htons(4747);
client_address.sin_addr.s_addr = inet_addr(routerIP.c_str());
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bind_flag = bind(sockfd, (struct sockaddr*) &client_address, sizeof(sockaddr_in));
int sent_bytes= sendto(sockfd, tablePacket.c_str(), 1024, 0, (struct sockaddr*) &server_address, sizeof(sockaddr_in));
*/
struct sockaddr_in router_address;
router_address.sin_family = AF_INET;
router_address.sin_port = htons(4747);
inet_pton(AF_INET,neighbors[i].c_str(),&router_address.sin_addr);
int sent_bytes = sendto(sockfd, tablePacket.c_str(), 1024, 0, (struct sockaddr*) &router_address, sizeof(sockaddr_in));
if(sent_bytes!=-1)
{
//cout<<"routing table "<<routerIP<<" sent to "<<neighbors[i]<<endl;
}
}
//cout<<"out of sendTable"<<endl;
}
void updateRoutingTableForNeighbor(string routerIP, vector<routingTableEntry> nip)
{cout<<"~~~~~~~~~~~~~~~~~~`in updateRoutingTableForNeighbor~~~~~~~~~~~~~~~~~~ "<<endl;}
//used in extractTableFromPacket
routingTableEntry getRouteEntry(string row, string delim)
{
char *t = new char[row.length()+1];
strcpy(t,row.c_str());
routingTableEntry rte;
vector<string> entries;
char *token = strtok(t,delim.c_str());
while(token!=NULL)
{
entries.push_back(token);
token = strtok(NULL,delim.c_str());
}
//rte.destination = entries[0];
rte.nextHop = entries[1];
rte.cost = atoi(entries[2].c_str());
entries.clear();
return rte;
}
void printRoutingTable(string selfIP)
{
cout<<"in printRoutingTable"<<endl;
cout<<"\t------\t"<<selfIP<<"\t------\t"<<endl;
cout<<"Destination \tNext Hop \tCost"<<endl;
cout<<"-------------\t-------------\t-----"<<endl;
auto it = routerSet.begin();
while(it != routerSet.end())
{
string ip = *it;
if(ip == selfIP){it++;continue;}
auto result = routingTable.find(ip);
routingTableEntry row = result -> second;
cout << ip << "\t\t" << row.nextHop<<"\t\t"<<row.cost << "\n";
it++;
}
cout<<"--------------------------------------"<<endl;
}
void printMap()
{
cout<<"\n~~~~~printing map~~~~~~~~~~~\n"<<endl;
for (auto it =routingTable.begin(); it !=routingTable.end(); ++it)
{
cout<<it->first << " "<<it->second.nextHop<< " "<< it->second.cost<<endl;
}
cout<<endl;
}
void receiveCommand(string routerIP)
{
cout<<"in receiveCommand"<<endl;
//socklen_t addrlen; //declaring it globally now
struct sockaddr_in server_address;
struct sockaddr_in router_address;
char buffer[1024];
server_address.sin_family = AF_INET;
server_address.sin_port = htons(4747);
server_address.sin_addr.s_addr = inet_addr(routerIP.c_str());
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bind_flag = bind(sockfd, (struct sockaddr*) &server_address, sizeof(sockaddr_in));
if(!bind_flag) cout<<"~~~~~~~~~~~~Connection successful~~~~~~~~~~~~~~"<<endl;
else cout<<"~~~~~~~~~~~~~~~Connection failed~~~~~~~~~~~~~~~~"<<endl;
cout<<"--------------------------------------"<<endl;
while(true)
{
bytes_received = recvfrom(sockfd, buffer, 1024, 0, (struct sockaddr*) &router_address, &addrlen);
cout<<"bytes_received "<<bytes_received<<endl;
/*cout<<"\n~~~~~~~~~~~~~~~~`printing buffer content~~~~~~~~~~~~~~~~~~~`"<<endl;
cout<<string(buffer)<<endl;
cout<<"~~~~~~~~~~~~~~~~`end of printing buffer content~~~~~~~~~~~~~~~~~~~\n"<<endl;
*/
if(bytes_received!=-1)
{
string recv(buffer);
string head = recv.substr(0,4);
cout<<"\nhead is " <<head <<endl;
cout<<"recv is "<<recv<<"\n"<<endl;
if(!head.compare("show"))
{
printRoutingTable(routerIP);
}
else if(!head.compare("clk "))
{
sendClock++;
//cout<<"clock "<<sendClock<<endl;
sendTable(routerIP);
}
else if(head[0] == ':')
{
int length = recv.length()-15;
char pckt[length];
for (int i=0; i<length; i++) {
pckt[i] = buffer[16+i];
}
string packet(pckt);
cout<<string(pckt)<<endl;
vector<routingTableEntry> neighbor = extractTableFromPacket(pckt);
updateRoutingTableForNeighbor(routerIP, neighbor);
}
}
}
}
int main(int argc,char *argv[]){
if(argc != 3){
cout<<"router : "<<argv[1]<<"<ip address>\n";
exit(1);
}
string routerIP = argv[1];
string topologyFile = argv[2];
initRouter(routerIP, topologyFile);
printRoutingTable(routerIP);
receiveCommand(routerIP);
close(sockfd);
return 0;
}
driver.py
import os
import socket
import struct
import sys
import threading
import time
class Driver(object):
def __init__(self, topo):
"""
constructor
"""
self.topo = topo
self.host = '192.168.0.100' # driver ip address
self.port = 4747 # port number must match the one in router.py
self.hosts = self.populate_hosts() # populate hosts
self.clk = 1 # number of sync clocks
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # open socket
self.s.bind((self.host, self.port)) # bind to socket
def populate_hosts(self):
"""
populates list of hosts
"""
temp = []
with open(self.topo) as f:
for line in f.readlines():
segments = line.split()
if segments[0] not in temp:
temp.append(segments[0])
if segments[1] not in temp:
temp.append(segments[1])
return temp
def show_hosts(self):
"""
shows a list of hosts
"""
for host in self.hosts: # iterate over hosts
print(host) # print host
def show_help(self):
"""
shows help menu
"""
print('list of commands')
print('----------------')
print('help - shows a list of available commands')
print('hosts - lists all hosts')
print('cost <ip1> <ip2> <cost> - updates link cost between ip1 and ip2')
print('down <ip1> <ip2> - deactivates link between ip1 and ip2')
print('up <ip1> <ip2> - reactivates link between ip1 and ip2')
print('send <ip1> <ip2> <message-length> <message> - instruct ip1 to send message to ip2')
print('show <ip> - instruct ip to show its routing table')
print('clear - clears the screen')
print('exit - terminates the driver')
def update_cost(self, command):
"""
send cost to relevant routers
Note: sending to relevant routers only
"""
# 1 -> h1, 2 -> h2, 3 -> cost
segments = command.split() # split command on spaces
if len(segments) != 4 or segments[1] not in self.hosts or segments[2] not in self.hosts: # sanity check
print('invalid arguments')
return
else:
h1 = map(int, segments[1].split('.'))
h2 = map(int, segments[2].split('.'))
for host in [segments[1], segments[2]]: # iterate over hosts
print('sending cost update to {0}'.format(host)) # print a message before sending to each host
buf = struct.pack('4s4B4Bh', segments[0], h1[0], h1[1], h1[2], h1[3], h2[0], h2[1], h2[2], h2[3], int(segments[3]))
self.s.sendto(buf, (host, self.port)) # send to each host
def send(self, command):
"""
sends message from source to destination
"""
# 1 -> src, 2 -> dest, 3:end -> message
segments = command.split() # split command on spaces
if len(segments) < 5 or segments[1] not in self.hosts or segments[2] not in self.hosts: # sanity check
print('invalid arguments')
return
else:
h1 = map(int, segments[1].split('.'))
h2 = map(int, segments[2].split('.'))
fmt = '4s4B4Bh' + segments[3] + 's'
buf = struct.pack(fmt, segments[0], h1[0], h1[1], h1[2], h1[3], h2[0], h2[1], h2[2], h2[3], int(segments[3]), ' '.join(segments[4:]))
print('sending to {0}'.format(segments[1])) # print a message before sending to source
self.s.sendto(buf, (segments[1], self.port)) # send to source
#self.s.sendto(command, (segments[1], self.port)) # send to source
def show_rt(self, command):
"""
instructs a router to show its routing table
"""
# 1 -> router
segments = command.split()
if len(segments) != 2 or segments[1] not in self.hosts:
print('invalid arguments')
return
else:
router = map(int,segments[1].split('.'))
fmt = '4s4B';
buf = struct.pack(fmt, segments[0], router[0], router[1], router[2], router[3])
print('sending to {0}'.format(segments[1]))
self.s.sendto(buf, (segments[1], self.port))
def link_down(self, command):
"""
deactivates link between two routers
Note: should be done both ways
"""
# 1 -> h1, 2 -> h2
segments = command.split()
if len(segments) != 3 or segments[1] not in self.hosts or segments[2] not in self.hosts: # sanity check
print('invalid arguments')
return
else:
os.system('sudo iptables -I OUTPUT -s {0} -d {1} -j DROP'.format(segments[1], segments[2])) # drop from h1 to h2
os.system('sudo iptables -I OUTPUT -s {0} -d {1} -j DROP'.format(segments[2], segments[1])) # drop from h2 to h1
def link_up(self, command):
"""
reactivates link between two routers
Note: should be done both ways
"""
# 1 -> h1, 2 -> h2
segments = command.split()
if len(segments) != 3 or segments[1] not in self.hosts or segments[2] not in self.hosts: # sanity check
print('invalid arguments')
return
else:
os.system('sudo iptables -I OUTPUT -s {0} -d {1} -j ACCEPT'.format(segments[1], segments[2])) # accept from h1 to h2
os.system('sudo iptables -I OUTPUT -s {0} -d {1} -j ACCEPT'.format(segments[2], segments[1])) # accept from h2 to h1
def send_clock(self):
"""
sends clock to routers to exchange routing table
"""
for host in self.hosts: # iterate over hosts
self.s.sendto('clk {0}'.format(self.clk), (host, self.port)) # send to each host
self.clk += 1 # increment clock
t = threading.Timer(5, self.send_clock) # get a reference to timer
t.daemon = True # mark it daemonic
t.start() # start timer
def run(self):
"""
runs in an infinite loop
"""
self.send_clock()
print('type help to see a list of commands')
while True:
self.command = raw_input('> ')
if self.command == 'help':
self.show_help()
elif self.command == 'hosts':
self.show_hosts()
elif self.command.startswith('cost'):
self.update_cost(self.command)
elif self.command.startswith('down'):
self.link_down(self.command)
elif self.command.startswith('up'):
self.link_up(self.command)
elif self.command.startswith('send'):
self.send(self.command)
elif self.command.startswith('show'):
self.show_rt(self.command)
elif self.command == 'clear':
os.system('clear')
elif self.command == 'exit':
break
def __del__(self):
"""
destructor
"""
self.s.close()
if __name__ == '__main__':
if len(sys.argv) < 2:
print('python driver.py <topo>')
sys.exit(0)
driver = Driver(sys.argv[1])
driver.run()
setup.sh
sudo ifconfig enp8s0:1 192.168.0.1 netmask 255.255.255.0 up
sudo ifconfig enp8s0:2 192.168.0.2 netmask 255.255.255.0 up
sudo ifconfig enp8s0:3 192.168.0.3 netmask 255.255.255.0 up
sudo ifconfig enp8s0:4 192.168.0.4 netmask 255.255.255.0 up
sudo ifconfig enp8s0:100 192.168.0.100 netmask 255.255.255.0 up
topo.txt
192.168.0.1 192.168.0.2 10
192.168.0.2 192.168.0.3 2
192.168.0.1 192.168.0.3 3
192.168.0.2 192.168.0.4 5
192.168.0.3 192.168.0.4 11
在终端中运行前两行,在另一个终端中运行第三行
g++ router.cpp -o router
./router <ip> topo.txt
python driver.py topo.txt
我跑步时的输出:
~~~~~~printing neighbors in initRouter~~~~~~~~~~~`
192.168.0.2
192.168.0.3
~~~~~printing map~~~~~~~~~~~
192.168.0.1 192.168.0.1 0
192.168.0.2 192.168.0.2 10
192.168.0.3 192.168.0.3 3
192.168.0.4 - 99999
in printRoutingTable
------ 192.168.0.1 ------
Destination Next Hop Cost
------------- ------------- -----
192.168.0.2 192.168.0.2 10
192.168.0.3 192.168.0.3 3
192.168.0.4 - 99999
--------------------------------------
in receiveCommand
~~~~~~~~~~~~Connection successful~~~~~~~~~~~~~~
--------------------------------------
bytes_received 5
head is clk
recv is clk 368.0.4
in send table
~~~~~~~~~in makeTableIntoPacket ~~~~~~~~~~~~
192.168.0.2#192.168.0.2#10192.168.0.3#192.168.0.3#3192.168.0.4#-#99999
tablePacket is :192.168.0.2#192.168.0.2#10192.168.0.3#192.168.0.3#3192.168.0.4#-#99999
bytes_received 5
head is clk
recv is clk 468.0.4
in send table
~~~~~~~~~in makeTableIntoPacket ~~~~~~~~~~~~
192.168.0.2#192.168.0.2#10192.168.0.3#192.168.0.3#3192.168.0.4#-#99999
tablePacket is :192.168.0.2#192.168.0.2#10192.168.0.3#192.168.0.3#3192.168.0.4#-#99999
bytes_received 5
head is clk
recv is clk 568.0.4
in send table
~~~~~~~~~in makeTableIntoPacket ~~~~~~~~~~~~
192.168.0.2#192.168.0.2#10192.168.0.3#192.168.0.3#3192.168.0.4#-#99999
tablePacket is :192.168.0.2#192.168.0.2#10192.168.0.3#192.168.0.3#3192.168.0.4#-#99999
所需的输出是:recv
应该获得整个数据包,即clk :192.168.0.2#192.168.0.2#10192.168.0.3#192.168.0.3#3192.168.0.4#-#99999
而不是clk <garbage>