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

以下是基于 ​​RDMA-Tutorial​​ 开源项目编写的可运行 RDMA 通信 Demo,包含完整的代码、编译和运行步骤,并结合实际场景进行说明。


​一、环境准备​

  1. ​硬件/模拟环境​
    • ​物理 RDMA 设备​​:若使用 Mellanox 网卡(如 ConnectX 系列),需安装 MLNX_OFED 驱动。
    • ​模拟环境​​:若无物理设备,可通过 ​​Soft-RoCE​​ 模拟(Ubuntu 示例): sudo apt install libibverbs-dev librdmacm-dev # 安装依赖 sudo modprobe rdma_rxe # 加载内核模块 sudo rxe_cfg add ens33 # 绑定网卡(替换为实际网卡名)
  2. ​克隆项目并编译​git clone https://github.com/jcxue/RDMA-Tutorial.git cd RDMA-Tutorial mkdir build && cd build cmake .. && make # 编译项目(需已安装 CMake)

​二、示例代码:RDMA 双向通信​

以下是一个简化的 ​​客户端-服务器​​ 双向通信 Demo,基于 librdmacmlibibverbs 实现零拷贝数据传输。

​代码文件:rdma_demo.c

#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;
}

​三、编译与运行​

  1. ​编译命令​gcc rdma_demo.c -o rdma_demo -lrdmacm -libverbs
  2. ​运行示例​
    • ​服务端​​(监听端口 12345): ./rdma_demo 12345
    • ​客户端​​(连接至服务端): ./rdma_demo 192.168.1.100 12345
  3. ​预期输出​
    • 服务端: Connection established. Data received: Hello from client!
    • 客户端: Send completed.

​四、关键机制解析​

  1. ​零拷贝传输​
    • 通过 rdma_reg_msgs() 注册内存缓冲区,RDMA 设备直接访问用户空间内存,避免内核拷贝。
  2. ​异步事件驱动​
    • 使用 rdma_get_cm_event() 监听连接事件,on_completion() 处理数据传输完成通知。
  3. ​连接管理​
    • librdmacm 抽象了 RDMA 连接建立过程,支持 TCP-like 的通信模式。

​五、常见问题解决​

  1. ​编译错误​​:确保安装 libibverbs-devlibrdmacm-dev
  2. ​连接失败​​:检查防火墙设置,确认服务端 IP 和端口正确。
  3. ​设备不可用​​:通过 ibv_devices 验证 RDMA 设备状态,或使用 Soft-RoCE 模拟。

​六、扩展应用场景​

  1. ​高性能计算​​:用于 MPI 进程间通信加速,减少延迟。
  2. ​分布式存储​​:结合 SPDK 实现高速存储访问。
  3. ​实时数据处理​​:在 Kafka/Pulsar 中优化消息队列吞吐量。

​参考文档​​:

此条目发表在未分类分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注