基于RDMA-Tutorial生成的测试代码

以下是基于 ​​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&#91;1]); // 服务端:./demo <port>
} else if (argc == 3) {
run_client(argv&#91;1], argv&#91;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">

​​运行示例​​

  • ​​服务端​​(监听端口 12345): ./rdma_demo 12345

  • ​​客户端​​(连接至服务端): ./rdma_demo 192.168.1.100 12345

​​预期输出​​

  • 服务端: Connection established. Data received: Hello from client!

  • 客户端: Send completed.

​​四、关键机制解析​​

​​零拷贝传输​​

  • 通过 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 配置指南

data-ad-format="auto" data-full-width-responsive="true">