【问题标题】:How can multiple client programs can share messages with each other simultaneously?多个客户端程序如何能够同时相互共享消息?
【发布时间】:2016-09-19 01:55:53
【问题描述】:

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

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

part-1) 从文件加载初始路由表。 [只是关于它的邻居的信息。] part-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() [每个路由器程序都会这样做]

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

我尝试过使用线程(从 cmets 可见),但在这种情况下,路由器不会按顺序接收发送的消息,因此“关闭”消息在其他消息之前到达并且它们停止运行 [关闭消息:将总路由表发送给邻居后,我将向该邻居发送“关闭”消息,以便它可以停止期待来自该路由器的消息。我正在检查是否所有邻居都将它们关闭,只有这样路由器才会停止执行“update_routing_table”]

请建议我如何将消息从多个路由器传递到其他数量的路由器,以使每个路由器都接收所有消息。

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

【问题讨论】:

    标签: c++ multithreading sockets unix networking


    【解决方案1】:

    如何将消息从多个路由器传递到另一个数量 路由器以它们每个都接收所有消息的方式。

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

    值得称赞的是,您曾尝试这样做,并且如此描述了由此产生的问题:

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

    好的,这就是你的问题陈述。接下来你写的是:

    我尝试过使用线程(从 cmets 可见),但在那 情况下,路由器不会按顺序接收发送的消息,

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

    你的下一步不应该是,“好吧,让我尝试随机更改代码,也许如果我使用线程它会起作用”。

    如果您不明白为什么您的代码无法正常工作,那么尝试您能想到的每一个随机更改都不太可能很有成效。这就像试图启动您的汽车,但汽车无法启动,而您认为,也许,如果您踢了一个后轮胎,汽车就会启动。

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

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

    我发现显示的代码有两个潜在问题,这可能解释了您原来的问题。

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

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

    UDP 不是可靠的协议

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

    如果您足够了解创建UDP 套接字,那么您应该已经知道UDP 不保证数据报的传递。这是一个不可靠的协议。这是你应该被教导的第一件事,或者任何描述UDP 的书都会告诉你的第一件事。您不能保证您发送的数据报将被传递。时期。句号。

    无论您使用一个线程还是一千个线程,如果您的代码是用 C++、Perl、Python 或任何其他语言编写的,都没有关系。无论您做什么,都无法保证您发送的任何内容都会收到。

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

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

    而且,无论您如何操作,您必须始终检查来自sendto()recvfrom() 的返回值,并采取适当的方法来处理返回值表明发送或接收的字节数较少的可能性.

    附: sendto()recvfrom() 都不会告诉您您发送的数据报是否丢失并且无法传递。由你来解决。

    【讨论】:

    • 现在我提供了所有用于路由器程序的代码。由于我使用的是虚拟网络接口(在同一台计算机上的 ubuntum 上),我认为不会接收到发送的数据(即不会丢弃任何数据包)。
    猜你喜欢
    • 1970-01-01
    • 2020-03-04
    • 2017-12-26
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多