OpenMPI多客户端连接服务器后如何构建单一通信域?
解决方案:让所有MPI客户端处于同一通信域
要让所有连接到服务器的客户端处于同一个通信域,你需要在服务器端逐步合并新客户端的通信连接,并将全局通信域的信息传递给客户端。以下是具体实现步骤和代码修改:
核心思路
- 服务器维护一个全局的客户端通信域(intra-comm),每次新客户端连接后,将其合并到这个全局域中。
- 利用OpenMPI的
ompi_global_scope全局范围特性,将合并后的通信域ID发送给客户端,客户端通过MPI_Comm_join获取这个全局通信域,从而实现客户端间的直接通信。
服务器代码修改
#include <mpi.h> #include <string> #include <iostream> using namespace std; int main(int argc, char *argv[]){ MPI_Status status; char portname[MPI_MAX_PORT_NAME]; MPI_Init(&argc,&argv); MPI_Info env = MPI_INFO_ENV; MPI_Info_set(env, "ompi_global_scope", "true"); MPI_Open_port(env, portname); MPI_Publish_name("service", env, portname); MPI_Comm client_comm = MPI_COMM_NULL; // 存储所有客户端的全局通信域 int client_count = 0; while (true) { MPI_Comm new_client_intercomm; // 接受新客户端连接,得到与单个客户端的inter-comm MPI_Comm_accept(portname, MPI_INFO_ENV, 0, MPI_COMM_WORLD, &new_client_intercomm); client_count++; if (client_comm == MPI_COMM_NULL) { // 处理第一个客户端:将inter-comm转为包含客户端的intra-comm MPI_Comm temp_comm; MPI_Intercomm_merge(new_client_intercomm, 1, &temp_comm); // 客户端作为rank 0 // 提取仅包含客户端的通信域 int client_rank = 0; MPI_Comm_create(temp_comm, &client_rank, 1, MPI_INFO_ENV, &client_comm); MPI_Comm_free(&temp_comm); } else { // 合并新客户端到现有全局通信域 // 先将新客户端的inter-comm转为仅包含客户端的intra-comm MPI_Comm new_client_intra; MPI_Intercomm_merge(new_client_intercomm, 1, &new_client_intra); int new_rank = 0; MPI_Comm new_client_only; MPI_Comm_create(new_client_intra, &new_rank, 1, MPI_INFO_ENV, &new_client_only); MPI_Comm_free(&new_client_intra); // 合并现有客户端域与新客户端域 MPI_Comm temp_union; MPI_Comm_union(client_comm, new_client_only, &temp_union); MPI_Comm_free(&client_comm); MPI_Comm_free(&new_client_only); client_comm = temp_union; } // 将全局通信域的ID发送给新客户端 char comm_id[MPI_MAX_OBJECT_NAME]; int len; MPI_Comm_get_name(client_comm, comm_id, &len); MPI_Send(comm_id, MPI_MAX_OBJECT_NAME, MPI_CHAR, 0, 0, new_client_intercomm); MPI_Comm_free(&new_client_intercomm); } MPI_Close_port(portname); MPI_Finalize(); }
客户端代码修改
#include<mpi.h> #include<iostream> #include<string> #include <unistd.h> using namespace std; int main(int argc, char *argv[]){ MPI_Comm server; char portname[MPI_MAX_PORT_NAME]; MPI_Init(&argc,&argv); MPI_Info env = MPI_INFO_ENV; MPI_Lookup_name("service", env, portname); MPI_Comm_connect(portname, MPI_INFO_ENV, 0, MPI_COMM_WORLD, &server); // 接收服务器发送的全局客户端通信域ID char comm_id[MPI_MAX_OBJECT_NAME]; MPI_Recv(comm_id, MPI_MAX_OBJECT_NAME, MPI_CHAR, 0, 0, server, MPI_STATUS_IGNORE); // 加入全局客户端通信域 MPI_Comm client_group_comm; MPI_Comm_join(comm_id, &client_group_comm); int rank, size; while (true) { sleep(3); MPI_Comm_rank(client_group_comm, &rank); MPI_Comm_size(client_group_comm, &size); cout<<"size:"<<size<<",rank:"<<rank<<endl; } MPI_Comm_disconnect(&server); MPI_Comm_free(&client_group_comm); MPI_Finalize(); }
关键注意点
- 必须设置
ompi_global_scope=true,确保通信域名称可以全局访问,MPI_Comm_join才能正常工作。 MPI_Comm_union用于合并两个intra-comm,生成包含所有进程的新通信域。- 服务器每次合并后都要释放临时通信域,避免资源泄漏。
内容的提问来源于stack exchange,提问作者du fei
相关产品推荐
相关产品推荐

