缓冲区未从套接字cpp接收发送的字节

时间:2018-12-10 21:03:02

标签: c++ sockets

我正在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>

0 个答案:

没有答案