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

How can multiple client programs can share messages with each other simultaneously?

本文关键字:共享 消息 何能够 客户端 程序      更新时间:2023-10-16

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

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

part-1)从文件中加载初始路由表。[只是关于它邻居的信息。]part-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]: %sn", 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]: %sn", 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]: %sn", inet_ntoa(dummy.sin_addr), ntohs(dummy.sin_port), buffer_R);

if(! data.compare("shutdown")){
cout<<"----------------------"<<endl;
printf("Received SHUTDOWN from: [%s:%hu]: %sn", 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 bindn");
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()[每个路由器程序都会这样做]

当我运行所有的路由器程序时,并不是所有的程序都接收到所有发送的数据。某些发送的数据永远不会被接收。[这是在不使用任何线程的情况下]

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

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

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

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

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

值得称赞的是,你试图做到这一点,你这样描述了由此产生的问题:

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

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

我尝试过使用线程(从注释中可见),但在在这种情况下,路由器没有按顺序接收发送的消息,

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

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

如果你不明白为什么你的代码不起作用,那么尝试你能想到的每一个随机更改都不太可能很有成效。这就像试图启动你的汽车,但汽车没有启动,你想,也许,如果你踢了一个后轮胎,就会让汽车启动。

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

您只显示了不完整的、孤立的代码片段,而不是最小的、完整的和可验证的示例。如果没有一个最低限度的、完整的、可验证的例子,就不可能有明确的答案。唯一可能的事情是仅根据您发布的代码来分析任何潜在的问题。

我看到显示的代码有两个潜在的问题,这可能解释了您最初的问题。

无法保证发送或接收的字节数

不检查来自sendto()recvfrom()的返回值。这两个函数都不能保证已发送或接收到请求的字节数。有关更多信息,请参阅相应功能的手册页面。

UDP不是一个可靠的协议

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

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

如果您使用一个线程、一千个线程,或者您的代码是用C++、Perl、Python或任何其他语言编写的,这都无关紧要。无论你做什么,你都不能保证你发送的任何东西都会被收到。

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

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

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

附言:sendto()recvfrom()都不会告诉您发送的数据报是否丢失并且无法发送。这取决于你自己。