多个客户端程序如何能够同时共享消息?

时间:2016-05-22 01:47:46

标签: c++ multithreading sockets unix networking

我尝试使用unix套接字和c ++实现距离矢量路由。

我正在运行多个客户端程序实例(每个都有一个虚拟网络接口的IP,因此它可以绑定到该IP)。每个客户端都试图模拟路由器。到目前为止,它做到了这一点 - >

part-1)从文件加载初始路由表。 [只是关于它的邻居的信息。] 第2部分)将其路由表信息发送给邻居。

我面临第2部分当前实施的问题。

//数据结构

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include<thread>
#include<bits/stdc++.h> 
#include <chrono>
using namespace std;

#define MAX 10000
#define MAXCHAR 2048

int sockfd;
int bind_flag;
int sent_bytes;
int bytes_received;
char buffer[MAXCHAR];

socklen_t addrlen;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
struct sockaddr_in dummy;


string ip1, ip2;
int cost;




struct routing_table_entry{
        string next_hop;
        int cost;
       routing_table_entry(){
   }


routing_table_entry(string next_hop, int cost){
    this->next_hop=next_hop;
    this->cost=cost;

}

};

map<string, routing_table_entry> routing_table;

路由表发件人功能

 void send_table_to_neighbor(){

    it = routing_table.begin();

    ostringstream message;

while(it!= routing_table.end()){

    if((it->first).compare((it->second).next_hop) ==0){ //neighbour check

        cout<<"Sending table to: "<<it->first<<endl;
        inet_pton(AF_INET,(it->first).c_str(),&server_address.sin_addr);
        cout<<"Neighbour IP: "<<it->first<<endl;
        nest = routing_table.begin();

        while(nest != routing_table.end()){
            message.clear();
            message.str("");
            // destination next hop cost
            message<< (nest->first)<<" "<<myIP<<" "<<(nest->second).cost<<" "; //destination

            string message_string = message.str();
            strcpy((char*)buffer_S, message_string.c_str());
            cout<<"Message string: "<<message_string<<endl;

            printf("Sending to: [%s:%hu]: %s\n", inet_ntoa(server_address.sin_addr), ntohs(server_address.sin_port), buffer_S);

            sent_bytes=sendto(sockfd, buffer_S, MAXCHAR, 0, (struct sockaddr*) &server_address, sizeof(sockaddr_in));

            int random = rand() % 2 + 1;
    //        std::this_thread::sleep_for (std::chrono::seconds(random));

            nest++;
        }


      string terminate = "shutdown";
      strcpy((char*)buffer_S, terminate.c_str());

        printf("Sending to: [%s:%hu]: %s\n", inet_ntoa(server_address.sin_addr), ntohs(server_address.sin_port), buffer_S);

      sent_bytes=sendto(sockfd, buffer_S, MAXCHAR, 0, (struct sockaddr*) &server_address, sizeof(sockaddr_in));

   // cout<<buffer <<endl;

   }

    int random = rand() % 3 + 2;
  //  std::this_thread::sleep_for (std::chrono::seconds(random));
    it++;
}

return;

}

接收表并更新表的函数。

  void update_routing_table(){
       cout<<"My IP: "<<myIP<<endl;

    while(true){

    addrlen= sizeof(dummy);
    cout<<"Started reading:...."<<endl;

    bytes_received = recvfrom(sockfd, buffer_R, MAXCHAR , 0, (struct sockaddr*) &dummy, &addrlen);
    //bytes_received = recvfrom(sockfd, buffer_R, MAXCHAR , 0, (struct sockaddr*) &dummy, &addrlen);

    cout<<"Stop reading:...."<<endl;

    string data(buffer_R);

    printf("Received from: [%s:%hu]: %s\n", inet_ntoa(dummy.sin_addr), ntohs(dummy.sin_port), buffer_R);


    if(! data.compare("shutdown")){
        cout<<"----------------------"<<endl;
        printf("Received SHUTDOWN from: [%s:%hu]: %s\n", inet_ntoa(dummy.sin_addr), ntohs(dummy.sin_port), buffer_R);
        cout<<"----------------------"<<endl;
        _count++;

        }
    if(_count==3)
        break;

  istringstream data_buff(data);


    string dest, next_hop;
    data_buff>>dest>>next_hop>>cost;
     cout<<"Receiving: "<<dest<<" "<<next_hop<<" "<<cost<<endl;

    it= routing_table.find(dest);

    if(it != routing_table.end()){

        //update the table
        temp = routing_table.find(next_hop); //next_hop is my neigbour

        if((temp->second).cost + cost < (it->second).cost ){ // A-B-X , (A->B) + (B->X) < (A->X)
            //it->second = routing_table_entry(next_hop, cost);
            routing_table[it->first]=routing_table_entry(next_hop, (temp->second).cost + cost);
            cout<<"Inside."<<endl;
            cout<<dest<<" "<<next_hop<<" "<<cost<<endl;
            cout<<it->first<<" "<<(it->second).next_hop<<" "<<(it->second).cost<<endl;
            cout<<"DEBUG"<<endl;

            print_routing_table();

          //  send_table_to_neighbor();

        }


    }
    //int random = rand() %2 +1;
 //     std::this_thread::sleep_for (std::chrono::seconds(random));
}

  return;

}

主要功能,

int main(int argc, char *argv[]){


if(argc != 2){
    printf("%s <ip address>\n", argv[0]);
    exit(1);
}
//FILE* topo=freopen("topo.txt", "r", stdin);

ifstream file("topo.txt");

 myIP=string(argv[1]);

string hold;

while(getline(file, hold)){

    istringstream input(hold);
    input>>ip1>>ip2>>cost;

    if(!myIP.compare(ip1))

        routing_table[ip2]=routing_table_entry(ip2, cost); // destination ip2, next hop ip2

    else if(!myIP.compare(ip2))

        routing_table[ip1]=routing_table_entry(ip1, cost); //destination ip1, next hop ip1

    else{

            it= routing_table.find(ip1);

            if(it == routing_table.end())
                routing_table[ip1]= routing_table_entry("-", MAX);

            it= routing_table.find(ip2);


            if(it == routing_table.end())
                routing_table[ip2]= routing_table_entry("-", MAX);
    }
}

file.close();


print_routing_table();

it= routing_table.begin();

server_address.sin_family = AF_INET;
server_address.sin_port = htons(4747);

client_address.sin_family = AF_INET;
client_address.sin_port = htons(4747);
//client_address.sin_addr.s_addr = inet_addr(argv[1]);
inet_pton(AF_INET,argv[1],&client_address.sin_addr);

sockfd = socket(AF_INET, SOCK_DGRAM, 0);
cout<< "Socket value "<<sockfd <<endl;
bind_flag = bind(sockfd, (struct sockaddr*) &client_address, sizeof(sockaddr_in));

if(bind_flag==0)
    printf("successful bind\n");

    send_table_to_neighbor();
    update_routing_table();

cout<<"<<My IP is: "<<myIP<<endl;
print_routing_table();


close(sockfd);


return 0;

 }

现在,从主函数,我调用i)send_table_to_neighbor()然后,ii)update_routing_table()[每个路由器程序将执行此操作]

当我运行所有路由器程序时,并非所有路由器程序都接收到所有已发送的数据。从未收到过一些发送的数据。 [这是没有使用任何线程]

我尝试过使用线程(从评论中可以看到),但在这种情况下,路由器不会按顺序接收发送的消息,因此&#34; shutdown&#34;消息在其他消息之前到达并且它们停止运行 [关闭消息:在将总路由表发送给邻居之后,我发送了一个&#34; shutdown&#34;向该邻居发送消息,以便它可以停止期望来自该路由器的消息。我检查所有邻居是否发送了关闭,然后路由器才会停止执行&#34; update_routing_table&#34;]

请建议我如何将消息从多个路由器传递到另一个路由器,每个路由器都会收到所有消息。

Topo.txt:http://codepad.org/Z0cDGHvX 虚拟网络接口的设置文件:http://codepad.org/MDoJzpTx

1 个答案:

答案 0 :(得分:1)

  

如何将消息从多个路由器传递到另一个路由器   路由器,每个路由器都接收所有消息。

这个问题的答案非常简单:只需编写代码即可。

值得赞扬的是,您试图这样做,因此您描述了由此产生的问题:

  

当我运行所有路由器程序时,并非所有路由器程序都接收全部   发送的数据

好的,这是你的问题陈述。你写的下一件事是:

  

我尝试过使用线程(从评论中可以看到),但是在那里   例如,路由器不按顺序接收发送的消息,

这就是你出错的地方。您首先将问题描述为“并非所有问题都接收到所有已发送的数据”。如果是这种情况,那么你的下一步应该是找出原因,然后解决它。

你的下一步不应该是,“好吧,让我尝试对代码进行随机更改,也许如果我使用线程就行了”。

如果您不理解为什么您的代码不起作用,那么尝试您可以想到的每个随机更改都不太可能非常高效。这就像试图启动你的汽车一样,汽车没有启动,你可能会想到,如果你踢了一个后轮胎,就会让汽车开始行驶。

不,你应该找出“并非所有人都收到所有发送数据”的确切原因。使用调试器或其他可用的工具进行调查。阅读有关您的代码正在执行的任何可用的技术文档。一旦你知道并理解了原因,那么下一步将是弄清楚如何应对它。

您只显示了不完整的,孤立的代码片段,而不是minimum, complete, and verifiable example。没有minimum, complete, an verifiable example没有明确的答案是可能的。唯一可能的做法是根据您发布的代码分析任何潜在的,可能的问题。

我看到显示的代码存在两个潜在问题,这可能解释了您原来的问题。

不保证发送或接收的字节数

未检查sendto()recvfrom()的返回值。这些功能中的任何一个都不能保证已发送或接收所请求的字节数。有关详细信息,请参见相应功能的手册页。

UDP不是可靠的协议

从显示的代码中,您是否创建了TCPUDP套接字并不是绝对清楚的。它似乎是UDP,因为您正在使用这些功能的网络地址参数。以下假设您使用的是UDP

如果您足够了解创建UDP套接字,那么您应该已经知道UDP不保证数据报传递。这是一个不可靠的协议。这是你应该教的第一件事,或者第一件描述UDP的书会告诉你。您无法保证将发送您发送的数据报。期。完全停止。

如果您的代码是用C ++,Perl,Python或任何其他语言编写的,那么使用一个线程,一千个线程并不重要。无论你做什么,你都无法保证你收到的任何东西都会被收到。

如果您确实使用UDP,那几乎可以确定这是您的问题。

如果您想使用UDP,并且需要可靠,有保证的数据报交付,则您有责任在UDP之上将其作为应用程序的一部分来实现。如果您不想这样做,请使用TCP

而且,就你如何做而言,你必须始终检查sendto()recvfrom()的返回值,并采用适当的方法来处理返回值表示更少字节的可能性被发送或接收。

P.S。 sendto()recvfrom()都不会告诉您发送的数据报是否丢失且无法发送。你可以自己解决这个问题。