2024年Windows平台C++开发InfiniBand RDMA的最小环境配置需求
Windows环境下基于InfiniBand实现跨机RDMA的最小C++示例配置方案
一、驱动与SDK准备
- 驱动:安装NVIDIA Mellanox ConnectX 4+ Windows驱动(2024年仍提供兼容版本),安装时必须勾选「Network Direct SPI」组件,确保网卡能被Network Direct接口识别。
- SDK:安装NVIDIA Mellanox Windows SDK,SDK中包含Network Direct的头文件(
ndspi.h)、静态库(nd.lib)及相关文档,默认安装路径为C:\Program Files\Mellanox\MLNX_WinOF2\SDK。
二、依赖库与项目配置
- 核心依赖库:
nd.lib(Network Direct SPI核心库)、ws2_32.lib(Windows TCP/IP辅助库,用于交换RDMA队列对信息)。 - VS项目配置:
- 将SDK的
include路径(如C:\Program Files\Mellanox\MLNX_WinOF2\SDK\include)添加到项目「附加包含目录」。 - 将SDK的
lib路径(如C:\Program Files\Mellanox\MLNX_WinOF2\SDK\lib\x64)添加到项目「附加库目录」。 - 在「附加依赖项」中加入
nd.lib;ws2_32.lib。
- 将SDK的
三、最小C++示例核心逻辑
通用初始化与清理
#include <windows.h> #include <ndspi.h> #include <winsock2.h> #include <iostream> // 初始化Network Direct环境 ND_STATUS InitND() { ND_STATUS status = NdStartup(); if (status != ND_SUCCESS) { std::cerr << "NdStartup failed: " << status << std::endl; return status; } return ND_SUCCESS; } // 清理Network Direct环境 void CleanupND() { NdShutdown(); }
服务端核心代码(简化版)
int ServerMain() { if (InitND() != ND_SUCCESS) return 1; // 获取本地RDMA适配器信息 ND_ADAPTER_INFO adapterInfo; ND_STATUS status = NdGetAdapterInfo(0, &adapterInfo, sizeof(adapterInfo)); if (status != ND_SUCCESS) { std::cerr << "NdGetAdapterInfo failed" << std::endl; CleanupND(); return 1; } // 创建保护域(PD) ND_PROTECTION_DOMAIN_HANDLE pd; status = NdCreateProtectionDomain(adapterInfo.AdapterHandle, NULL, &pd); if (status != ND_SUCCESS) { std::cerr << "NdCreateProtectionDomain failed" << std::endl; NdClose(adapterInfo.AdapterHandle); CleanupND(); return 1; } // 创建队列对(QP)、内存区域(MR)等资源(省略参数细节,需匹配客户端配置) ND_QUEUE_PAIR_HANDLE qpHandle; // ... 此处补充创建QP、MR的代码 // 用TCP交换QP地址信息(省略TCP服务端监听、连接逻辑) // 发送本地QP地址到客户端,接收客户端QP地址 // 建立QP连接并发送数据 ND_CONNECT_PARAMS connectParams = {0}; // 填充remoteQpAddress等参数 status = NdConnect(pd, qpHandle, &connectParams, NULL); if (status == ND_SUCCESS) { char sendBuf[] = "RDMA Cross-Machine Test"; NdSend(pd, qpHandle, sendBuf, sizeof(sendBuf), NULL, 0, NULL); } // 清理资源 NdClose(qpHandle); NdClose(pd); NdClose(adapterInfo.AdapterHandle); CleanupND(); return 0; }
客户端核心代码(简化版)
int ClientMain() { if (InitND() != ND_SUCCESS) return 1; // 获取本地RDMA适配器信息 ND_ADAPTER_INFO adapterInfo; ND_STATUS status = NdGetAdapterInfo(0, &adapterInfo, sizeof(adapterInfo)); if (status != ND_SUCCESS) { std::cerr << "NdGetAdapterInfo failed" << std::endl; CleanupND(); return 1; } // 创建保护域(PD) ND_PROTECTION_DOMAIN_HANDLE pd; status = NdCreateProtectionDomain(adapterInfo.AdapterHandle, NULL, &pd); if (status != ND_SUCCESS) { std::cerr << "NdCreateProtectionDomain failed" << std::endl; NdClose(adapterInfo.AdapterHandle); CleanupND(); return 1; } // 创建队列对(QP)、内存区域(MR)等资源(省略参数细节,需匹配服务端配置) ND_QUEUE_PAIR_HANDLE qpHandle; // ... 此处补充创建QP、MR的代码 // 用TCP连接服务端,交换QP地址信息(省略TCP客户端连接逻辑) // 接收服务端QP地址,发送本地QP地址 // 等待接收数据 char recvBuf[1024] = {0}; NdReceive(pd, qpHandle, recvBuf, sizeof(recvBuf), NULL, 0, NULL); std::cout << "Received data: " << recvBuf << std::endl; // 清理资源 NdClose(qpHandle); NdClose(pd); NdClose(adapterInfo.AdapterHandle); CleanupND(); return 0; }
四、关键注意事项
- 两台机器需处于同一InfiniBand网络,网卡已完成基础配置(如IPoIB或专用RDMA网络)。
- 防火墙需允许TCP辅助通信的自定义端口(如示例中使用的5555端口)。
- 内存区域(MR)需使用RDMA可访问内存,推荐用
NdAllocateMemory分配,或通过VirtualLock锁定用户态内存。
内容的提问来源于stack exchange,提问作者Tom McLean
相关产品推荐
相关产品推荐

