以下是基于 RDMA-Tutorial 开源项目编写的可运行 RDMA 通信 Demo,包含完整的代码、编译和运行步骤,并结合实际场景进行说明。
一、环境准备
硬件/模拟环境
物理 RDMA 设备:若使用 Mellanox 网卡(如 ConnectX 系列),需安装 MLNX_OFED 驱动。
模拟环境:若无物理设备,可通过 Soft-RoCE 模拟(Ubuntu 示例): sudo apt install libibverbs-dev librdmacm-dev # 安装依赖 sudo modprobe rdma_rxe # 加载内核模块 sudo rxe_cfg add ens33 # 绑定网卡(替换为实际网卡名)
克隆项目并编译 git clone https://github.com/jcxue/RDMA-Tutorial.git cd RDMA-Tutorial mkdir build && cd build cmake .. && make # 编译项目(需已安装 CMake)
二、示例代码:RDMA 双向通信
以下是一个简化的 客户端-服务器 双向通信 Demo,基于 librdmacm 和 libibverbs 实现零拷贝数据传输。
代码文件:rdma_demo.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include <stdio.h> #include <stdlib.h> #include <rdma/rdma_cma.h>
#define BUFFER_SIZE 1024
struct context { struct rdma_cm_id *id; struct ibv_mr *mr; char *buffer; };
// 连接建立回调 static void on_connect(struct rdma_cm_id *id) { struct context *ctx = (struct context *)id->context; printf("Connection established.\n"); }
// 数据接收回调 static void on_completion(struct ibv_wc *wc) { if (wc->status == IBV_WC_SUCCESS) { printf("Data received: %s\n", (char *)wc->wr_id); } }
// 服务端初始化 void run_server(const char *port) { struct rdma_cm_event *event; struct rdma_cm_id *listen_id; struct rdma_addrinfo hints = { .ai_flags = RAI_PASSIVE }; // 创建监听端 rdma_create_addr_info(&listen_id, NULL, port, &hints); rdma_listen(listen_id, 5); while (1) { rdma_get_cm_event(listen_id->channel, &event); if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) { struct context *ctx = malloc(sizeof(struct context)); ctx->id = event->id; ctx->buffer = malloc(BUFFER_SIZE); ctx->mr = rdma_reg_msgs(ctx->id, ctx->buffer, BUFFER_SIZE); rdma_accept(ctx->id, NULL); // 接受连接 } rdma_ack_cm_event(event); } }
// 客户端初始化 void run_client(const char *server_ip, const char *port) { struct rdma_cm_id *conn_id; struct rdma_addrinfo hints = { .ai_port_space = RDMA_PS_TCP }; struct ibv_wc wc; // 建立连接 rdma_create_addr_info(&conn_id, server_ip, port, &hints); rdma_connect(conn_id, NULL); // 发送数据 char *msg = "Hello from client!"; rdma_post_send(conn_id, NULL, msg, strlen(msg)+1, conn_id->mr, 0); rdma_get_send_comp(conn_id, &wc); // 等待发送完成 }
int main(int argc, char **argv) { if (argc == 2) { run_server(argv[1]); // 服务端:./demo <port> } else if (argc == 3) { run_client(argv[1], argv[2]); // 客户端:./demo <server_ip> <port> } return 0; }
|
三、编译与运行
编译命令 gcc rdma_demo.c -o rdma_demo -lrdmacm -libverbs
data-ad-format="fluid"
data-ad-layout-key="-7k+ex-4a-9w+4a">
运行示例
预期输出
四、关键机制解析
零拷贝传输
- 通过 rdma_reg_msgs() 注册内存缓冲区,RDMA 设备直接访问用户空间内存,避免内核拷贝。
异步事件驱动
- 使用 rdma_get_cm_event() 监听连接事件,on_completion() 处理数据传输完成通知。
连接管理
- librdmacm 抽象了 RDMA 连接建立过程,支持 TCP-like 的通信模式。
五、常见问题解决
编译错误:确保安装 libibverbs-dev 和 librdmacm-dev。
连接失败:检查防火墙设置,确认服务端 IP 和端口正确。
设备不可用:通过 ibv_devices 验证 RDMA 设备状态,或使用 Soft-RoCE 模拟。
六、扩展应用场景
高性能计算:用于 MPI 进程间通信加速,减少延迟。
分布式存储:结合 SPDK 实现高速存储访问。
实时数据处理:在 Kafka/Pulsar 中优化消息队列吞吐量。
参考文档:
RDMA-Tutorial 项目主页
Mellanox RDMA 编程手册
Soft-RoCE 配置指南