RDMA编程实践-SEND-RECEICVE原语应用

RDMA编程实践

本文描述了RDMA编程过程中的SEND-RECEIVE双边原语的代码实现。包含多个版本,1、client向server发送消息,server回复client收到消息(ACK),然后两边断开连接。2、server端循环等待客户端建立连接,client发送一次消息后,双方断开连接。3、server端循环等待客户端建立连接,一旦建立,client端可以一直向server端发送消息,直到发送消息为disconnect,server和client断开链接,但是server此时仍然可以等待别的client发送消息。
代码基于代码基于send-receive样例实现。关于代码注释,可以参考代码解释:
Makefile文件、会编译当前目录下的所有.c文件:

.PHONY: all cleanCC := gcc
CFLAGS := -Wall -g
LDLIBS := -lrdmacm -libverbs -lpthread -gSRCS := $(wildcard *.c)
APPS := $(SRCS:.c=)all: $(APPS)%: %.c$(CC) $(CFLAGS) $< -o $@ $(LDLIBS)clean:rm -f $(APPS)

version1 客户端-服务端消息一次传递

在这个阶段,我们希望能实现下面这样一个场景。client与server端相连接,client端能够发送一条消息给server,server收到该条消息之后恢复一条消息给client端表示我已经确认收到。之后两者断开连接。

代码:

// client1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <getopt.h>
#include <rdma/rdma_cma.h>
#include <rdma/rdma_verbs.h>static const char *server = "10.10.10.1";
static const char *port = "7471";static struct rdma_cm_id *id;
static struct ibv_mr *mr, *send_mr;
static int send_flags;
static uint8_t send_msg[16];
static uint8_t recv_msg[16];static int run(void)
{struct rdma_addrinfo hints, *res;struct ibv_qp_init_attr attr;struct ibv_wc wc;int ret;memset(&hints, 0, sizeof hints);hints.ai_port_space = RDMA_PS_TCP;ret = rdma_getaddrinfo(server, port, &hints, &res);if (ret) {printf("rdma_getaddrinfo: %s\n", gai_strerror(ret));goto out;}memset(&attr, 0, sizeof attr);attr.cap.max_send_wr = attr.cap.max_recv_wr = 1;attr.cap.max_send_sge = attr.cap.max_recv_sge = 1;attr.cap.max_inline_data = 16;attr.qp_context = id;attr.sq_sig_all = 1;ret = rdma_create_ep(&id, res, NULL, &attr);// Check to see if we got inline data allowed or notif (attr.cap.max_inline_data >= 16)send_flags = IBV_SEND_INLINE;elseprintf("rdma_client: device doesn't support IBV_SEND_INLINE, ""using sge sends\n");if (ret) {perror("rdma_create_ep");goto out_free_addrinfo;}mr = rdma_reg_msgs(id, recv_msg, 16);if (!mr) {perror("rdma_reg_msgs for recv_msg");ret = -1;goto out_destroy_ep;}if ((send_flags & IBV_SEND_INLINE) == 0) {send_mr = rdma_reg_msgs(id, send_msg, 16);if (!send_mr) {perror("rdma_reg_msgs for send_msg");ret = -1;goto out_dereg_recv;}}ret = rdma_post_recv(id, NULL, recv_msg, 16, mr);if (ret) {perror("rdma_post_recv");goto out_dereg_send;}ret = rdma_connect(id, NULL);if (ret) {perror("rdma_connect");goto out_dereg_send;}printf("client send: %s\n", (char *)send_msg);ret = rdma_post_send(id, NULL, send_msg, 16, send_mr, send_flags);if (ret) {perror("rdma_post_send");goto out_disconnect;}while ((ret = rdma_get_send_comp(id, &wc)) == 0);if (ret < 0) {perror("rdma_get_send_comp");goto out_disconnect;}while ((ret = rdma_get_recv_comp(id, &wc)) == 0);if (ret < 0)perror("rdma_get_recv_comp");elseret = 0;printf("client received: %s\n", (char *) recv_msg);out_disconnect:rdma_disconnect(id);
out_dereg_send:if ((send_flags & IBV_SEND_INLINE) == 0)rdma_dereg_mr(send_mr);
out_dereg_recv:rdma_dereg_mr(mr);
out_destroy_ep:rdma_destroy_ep(id);
out_free_addrinfo:rdma_freeaddrinfo(res);
out:return ret;
}int main(int argc, char **argv)
{int ret;char *s = "hello world";// printf("client send: %s\n", s);memcpy(send_msg, s , strlen(s));printf("rdma_client: start\n");ret = run();printf("rdma_client: end %d\n", ret);return ret;
}

server端代码

// server1.c
/** Copyright (c) 2005-2009 Intel Corporation.  All rights reserved.** This software is available to you under the OpenIB.org BSD license* below:**     Redistribution and use in source and binary forms, with or*     without modification, are permitted provided that the following*     conditions are met:**      - Redistributions of source code must retain the above*        copyright notice, this list of conditions and the following*        disclaimer.**      - Redistributions in binary form must reproduce the above*        copyright notice, this list of conditions and the following*        disclaimer in the documentation and/or other materials*        provided with the distribution.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE* SOFTWARE.*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <netdb.h>
#include <rdma/rdma_cma.h>
#include <rdma/rdma_verbs.h>static const char *server = "0.0.0.0";
static const char *port = "7471";static struct rdma_cm_id *listen_id, *id;
static struct ibv_mr *mr, *send_mr;
static int send_flags;
static uint8_t send_msg[16];
static uint8_t recv_msg[16];static int run(void)
{struct rdma_addrinfo hints, *res;struct ibv_qp_init_attr init_attr;struct ibv_qp_attr qp_attr;struct ibv_wc wc;int ret;memset(&hints, 0, sizeof hints);hints.ai_flags = RAI_PASSIVE;hints.ai_port_space = RDMA_PS_TCP;ret = rdma_getaddrinfo(server, port, &hints, &res);if (ret) {printf("rdma_getaddrinfo: %s\n", gai_strerror(ret));return ret;}memset(&init_attr, 0, sizeof init_attr);init_attr.cap.max_send_wr = init_attr.cap.max_recv_wr = 1;init_attr.cap.max_send_sge = init_attr.cap.max_recv_sge = 1;init_attr.cap.max_inline_data = 16;init_attr.sq_sig_all = 1;ret = rdma_create_ep(&listen_id, res, NULL, &init_attr);if (ret) {perror("rdma_create_ep");goto out_free_addrinfo;}ret = rdma_listen(listen_id, 0);if (ret) {perror("rdma_listen");goto out_destroy_listen_ep;}ret = rdma_get_request(listen_id, &id);if (ret) {perror("rdma_get_request");goto out_destroy_listen_ep;}memset(&qp_attr, 0, sizeof qp_attr);memset(&init_attr, 0, sizeof init_attr);ret = ibv_query_qp(id->qp, &qp_attr, IBV_QP_CAP,&init_attr);if (ret) {perror("ibv_query_qp");goto out_destroy_accept_ep;}if (init_attr.cap.max_inline_data >= 16)send_flags = IBV_SEND_INLINE;elseprintf("rdma_server: device doesn't support IBV_SEND_INLINE, ""using sge sends\n");mr = rdma_reg_msgs(id, recv_msg, 16);if (!mr) {ret = -1;perror("rdma_reg_msgs for recv_msg");goto out_destroy_accept_ep;}if ((send_flags & IBV_SEND_INLINE) == 0) {send_mr = rdma_reg_msgs(id, send_msg, 16);if (!send_mr) {ret = -1;perror("rdma_reg_msgs for send_msg");goto out_dereg_recv;}}ret = rdma_post_recv(id, NULL, recv_msg, 16, mr);if (ret) {perror("rdma_post_recv");goto out_dereg_send;}ret = rdma_accept(id, NULL);if (ret) {perror("rdma_accept");goto out_dereg_send;}while ((ret = rdma_get_recv_comp(id, &wc)) == 0);if (ret < 0) {perror("rdma_get_recv_comp");goto out_disconnect;}printf("server received: %s\n" , (char *)recv_msg);char *s = "ACK";memcpy(send_msg, s, strlen(s));printf("server send: %s\n", (char *)send_msg);ret = rdma_post_send(id, NULL, send_msg, 16, send_mr, send_flags);if (ret) {perror("rdma_post_send");goto out_disconnect;}while ((ret = rdma_get_send_comp(id, &wc)) == 0);if (ret < 0)perror("rdma_get_send_comp");elseret = 0;out_disconnect:rdma_disconnect(id);
out_dereg_send:if ((send_flags & IBV_SEND_INLINE) == 0)rdma_dereg_mr(send_mr);
out_dereg_recv:rdma_dereg_mr(mr);
out_destroy_accept_ep:rdma_destroy_ep(id);
out_destroy_listen_ep:rdma_destroy_ep(listen_id);
out_free_addrinfo:rdma_freeaddrinfo(res);return ret;
}int main(int argc, char **argv)
{int ret;printf("rdma_server: start\n");ret = run();printf("rdma_server: end %d\n", ret);return ret;
}

首先make编译完之后,在server端执行 ./server1,然后在客户端执行./client1
运行结果:
在这里插入图片描述
在这里插入图片描述
可以看到 client向server发送了hello world,server收到之后打印出来并回复给client端ACK消息,client收到之后并打印。最后双方断开连接,完成!

version2-客户端发送一次,服务端循环等待

client2的代码跟上面一样,server2代码不一样。
server2的逻辑:在run函数进来之后记录一个connect点,当远程客户端发送完信息后,释放连接的资源,跳转到connect阶段准备让下一个client连接。

/** Copyright (c) 2005-2009 Intel Corporation.  All rights reserved.** This software is available to you under the OpenIB.org BSD license* below:**     Redistribution and use in source and binary forms, with or*     without modification, are permitted provided that the following*     conditions are met:**      - Redistributions of source code must retain the above*        copyright notice, this list of conditions and the following*        disclaimer.**      - Redistributions in binary form must reproduce the above*        copyright notice, this list of conditions and the following*        disclaimer in the documentation and/or other materials*        provided with the distribution.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE* SOFTWARE.*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <netdb.h>
#include <rdma/rdma_cma.h>
#include <rdma/rdma_verbs.h>#define N 100
#define MAX_CAP 32static const char *server = "0.0.0.0";
static const char *port = "7471";static struct rdma_cm_id *listen_id, *id;
static struct ibv_mr *mr, *send_mr;
static int send_flags;
static uint8_t send_msg[MAX_CAP];
static uint8_t recv_msg[MAX_CAP];static int run(void)
{struct rdma_addrinfo hints, *res;struct ibv_qp_init_attr init_attr;struct ibv_qp_attr qp_attr;struct ibv_wc wc;int ret;while(1){memset(&hints, 0, sizeof hints);hints.ai_flags = RAI_PASSIVE;hints.ai_port_space = RDMA_PS_TCP;ret = rdma_getaddrinfo(server, port, &hints, &res);if (ret) {printf("rdma_getaddrinfo: %s\n", gai_strerror(ret));return ret;}memset(&init_attr, 0, sizeof init_attr);init_attr.cap.max_send_wr = init_attr.cap.max_recv_wr = N;init_attr.cap.max_send_sge = init_attr.cap.max_recv_sge = 1;init_attr.cap.max_inline_data = MAX_CAP;init_attr.sq_sig_all = 1;ret = rdma_create_ep(&listen_id, res, NULL, &init_attr);if (ret) {perror("rdma_create_ep");goto out_free_addrinfo;}ret = rdma_listen(listen_id, 0);if (ret) {perror("rdma_listen");goto out_destroy_listen_ep;}ret = rdma_get_request(listen_id, &id);if (ret) {perror("rdma_get_request");goto out_destroy_listen_ep;}memset(&qp_attr, 0, sizeof qp_attr);memset(&init_attr, 0, sizeof init_attr);ret = ibv_query_qp(id->qp, &qp_attr, IBV_QP_CAP,&init_attr);if (ret) {perror("ibv_query_qp");goto out_destroy_accept_ep;}if (init_attr.cap.max_inline_data >= MAX_CAP)send_flags = IBV_SEND_INLINE;elseprintf("rdma_server: device doesn't support IBV_SEND_INLINE, ""using sge sends\n");mr = rdma_reg_msgs(id, recv_msg, N);if (!mr) {ret = -1;perror("rdma_reg_msgs for recv_msg");goto out_destroy_accept_ep;}if ((send_flags & IBV_SEND_INLINE) == 0) {send_mr = rdma_reg_msgs(id, send_msg, MAX_CAP);if (!send_mr) {ret = -1;perror("rdma_reg_msgs for send_msg");goto out_dereg_recv;}}   ret = rdma_accept(id, NULL);if (ret) {perror("rdma_accept");goto out_dereg_send;}memset(recv_msg, 0 , sizeof recv_msg);memset(send_msg, 0 , sizeof send_msg);ret = rdma_post_recv(id, NULL, recv_msg, MAX_CAP, mr);if (ret) {perror("rdma_post_recv");goto out_dereg_send;}while ((ret = rdma_get_recv_comp(id, &wc)) == 0);if (ret < 0) {perror("rdma_get_recv_comp");goto out_disconnect;}printf("server received: %s\n", (char *)recv_msg);memcpy(send_msg, recv_msg, sizeof(recv_msg));ret = rdma_post_send(id, NULL, send_msg, MAX_CAP, send_mr, send_flags);if (ret) {perror("rdma_post_send");goto out_disconnect;}while ((ret = rdma_get_send_comp(id, &wc)) == 0); // 确认对方已经收到 对方会发送ackif (ret < 0)perror("rdma_get_send_comp");elseret = 0;rdma_disconnect(id);if ((send_flags & IBV_SEND_INLINE) == 0)rdma_dereg_mr(send_mr);rdma_dereg_mr(mr);rdma_destroy_ep(id);rdma_destroy_ep(listen_id);rdma_freeaddrinfo(res);  }out_disconnect:rdma_disconnect(id);
out_dereg_send:if ((send_flags & IBV_SEND_INLINE) == 0)rdma_dereg_mr(send_mr);
out_dereg_recv:rdma_dereg_mr(mr);
out_destroy_accept_ep:rdma_destroy_ep(id);
out_destroy_listen_ep:rdma_destroy_ep(listen_id);
out_free_addrinfo:rdma_freeaddrinfo(res);  return ret;
}int main(int argc, char **argv)
{int ret;printf("rdma_server: start\n");ret = run();printf("rdma_server: end %d\n", ret);return ret;
}

运行结果:
在这里插入图片描述

在这里插入图片描述

可以看到客户端发送一次消息之后便结束了,服务端却一直等待连接,直到按下ctrl+c。

version3-客户端循环发送,服务端循环等待,一次连接

和上述版本2不同的时候,这里client和server只连接一次,然后可以多次发送消息。直到client发送的消息为disconnect

// client3.c
/** Copyright (c) 2010 Intel Corporation.  All rights reserved.** This software is available to you under the OpenIB.org BSD license* below:**     Redistribution and use in source and binary forms, with or*     without modification, are permitted provided that the following*     conditions are met:**      - Redistributions of source code must retain the above*        copyright notice, this list of conditions and the following*        disclaimer.**      - Redistributions in binary form must reproduce the above*        copyright notice, this list of conditions and the following*        disclaimer in the documentation and/or other materials*        provided with the distribution.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE* SOFTWARE.*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <getopt.h>
#include <rdma/rdma_cma.h>
#include <rdma/rdma_verbs.h>#define N 100
#define MAX_CAP 32static const char *server = "10.10.10.1";
static const char *port = "7471";static struct rdma_cm_id *id;
static struct ibv_mr *mr, *send_mr;
static int send_flags;
static uint8_t send_msg[MAX_CAP];
static uint8_t recv_msg[MAX_CAP];static int run(void)
{struct rdma_addrinfo hints, *res;struct ibv_qp_init_attr attr;struct ibv_wc wc;int ret;memset(&hints, 0, sizeof hints);hints.ai_port_space = RDMA_PS_TCP;ret = rdma_getaddrinfo(server, port, &hints, &res);if (ret) {printf("rdma_getaddrinfo: %s\n", gai_strerror(ret));goto out;}memset(&attr, 0, sizeof attr);attr.cap.max_send_wr = attr.cap.max_recv_wr = 5;attr.cap.max_send_sge = attr.cap.max_recv_sge = 1;attr.cap.max_inline_data = MAX_CAP;attr.qp_context = id;attr.sq_sig_all = 1;ret = rdma_create_ep(&id, res, NULL, &attr);// Check to see if we got inline data allowed or notif (attr.cap.max_inline_data >= MAX_CAP)send_flags = IBV_SEND_INLINE;elseprintf("rdma_client: device doesn't support IBV_SEND_INLINE, ""using sge sends\n");if (ret) {perror("rdma_create_ep");goto out_free_addrinfo;}mr = rdma_reg_msgs(id, recv_msg, MAX_CAP);if (!mr) {perror("rdma_reg_msgs for recv_msg");ret = -1;goto out_destroy_ep;}if ((send_flags & IBV_SEND_INLINE) == 0) {send_mr = rdma_reg_msgs(id, send_msg, MAX_CAP);if (!send_mr) {perror("rdma_reg_msgs for send_msg");ret = -1;goto out_dereg_recv;}}// ret = rdma_post_recv(id, NULL, recv_msg, 16, mr);// if (ret) {//     perror("rdma_post_recv");//     goto out_dereg_send;// }// printf("123\n");ret = rdma_connect(id, NULL);if (ret) {perror("rdma_connect");goto out_dereg_send;}while(1){// sleep(5);memset(recv_msg, 0 , sizeof recv_msg);memset(send_msg, 0 , sizeof send_msg);printf("input send message: ");scanf("%s", send_msg);getchar();ret = rdma_post_recv(id, NULL, recv_msg, MAX_CAP, mr);if (ret) {perror("rdma_post_recv");goto out_dereg_send;}ret = rdma_post_send(id, NULL, send_msg, MAX_CAP, send_mr, send_flags);if (ret) {perror("rdma_post_send");goto out_disconnect;}while ((ret = rdma_get_send_comp(id, &wc)) == 0);if (ret < 0) {perror("rdma_get_send_comp");goto out_disconnect;}while ((ret = rdma_get_recv_comp(id, &wc)) == 0);if (ret < 0)perror("rdma_get_recv_comp");elseret = 0;if(strcmp((char*)send_msg,"disconnect") == 0){printf("disconnect\n");goto out_disconnect;}else{printf("%s\n", recv_msg);}}out_disconnect:rdma_disconnect(id);
out_dereg_send:if ((send_flags & IBV_SEND_INLINE) == 0)rdma_dereg_mr(send_mr);
out_dereg_recv:rdma_dereg_mr(mr);
out_destroy_ep:rdma_destroy_ep(id);
out_free_addrinfo:rdma_freeaddrinfo(res);
out:return ret;}int main(int argc, char **argv)
{int ret;//memcpy(send_msg, argv[1], 50);// while ((op = getopt(argc, argv, "s:p:")) != -1) {// 	switch (op) {// 	case 's':// 		server = optarg;// 		break;// 	case 'p':// 		port = optarg;// 		break;// 	default:// 		printf("usage: %s\n", argv[0]);// 		printf("\t[-s server_address]\n");// 		printf("\t[-p port_number]\n");// 		exit(1);// 	}// }printf("rdma_client: start\n");ret = run();printf("rdma_client: end %d\n", ret);return ret;
}
// server3.c
/** Copyright (c) 2005-2009 Intel Corporation.  All rights reserved.** This software is available to you under the OpenIB.org BSD license* below:**     Redistribution and use in source and binary forms, with or*     without modification, are permitted provided that the following*     conditions are met:**      - Redistributions of source code must retain the above*        copyright notice, this list of conditions and the following*        disclaimer.**      - Redistributions in binary form must reproduce the above*        copyright notice, this list of conditions and the following*        disclaimer in the documentation and/or other materials*        provided with the distribution.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE* SOFTWARE.*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <netdb.h>
#include <rdma/rdma_cma.h>
#include <rdma/rdma_verbs.h>#define N 100
#define MAX_CAP 32static const char *server = "0.0.0.0";
static const char *port = "7471";static struct rdma_cm_id *listen_id, *id;
static struct ibv_mr *mr, *send_mr;
static int send_flags;
static uint8_t send_msg[MAX_CAP];
static uint8_t recv_msg[MAX_CAP];static int run(void)
{struct rdma_addrinfo hints, *res;struct ibv_qp_init_attr init_attr;struct ibv_qp_attr qp_attr;struct ibv_wc wc;int ret;connect:memset(&hints, 0, sizeof hints);hints.ai_flags = RAI_PASSIVE;hints.ai_port_space = RDMA_PS_TCP;ret = rdma_getaddrinfo(server, port, &hints, &res);if (ret) {printf("rdma_getaddrinfo: %s\n", gai_strerror(ret));return ret;}memset(&init_attr, 0, sizeof init_attr);init_attr.cap.max_send_wr = init_attr.cap.max_recv_wr = N;init_attr.cap.max_send_sge = init_attr.cap.max_recv_sge = 1;init_attr.cap.max_inline_data = MAX_CAP;init_attr.sq_sig_all = 1;ret = rdma_create_ep(&listen_id, res, NULL, &init_attr);if (ret) {perror("rdma_create_ep");goto out_free_addrinfo;}ret = rdma_listen(listen_id, 0);if (ret) {perror("rdma_listen");goto out_destroy_listen_ep;}ret = rdma_get_request(listen_id, &id);if (ret) {perror("rdma_get_request");goto out_destroy_listen_ep;}memset(&qp_attr, 0, sizeof qp_attr);memset(&init_attr, 0, sizeof init_attr);ret = ibv_query_qp(id->qp, &qp_attr, IBV_QP_CAP,&init_attr);if (ret) {perror("ibv_query_qp");goto out_destroy_accept_ep;}if (init_attr.cap.max_inline_data >= MAX_CAP)send_flags = IBV_SEND_INLINE;elseprintf("rdma_server: device doesn't support IBV_SEND_INLINE, ""using sge sends\n");mr = rdma_reg_msgs(id, recv_msg, N);if (!mr) {ret = -1;perror("rdma_reg_msgs for recv_msg");goto out_destroy_accept_ep;}if ((send_flags & IBV_SEND_INLINE) == 0) {send_mr = rdma_reg_msgs(id, send_msg, MAX_CAP);if (!send_mr) {ret = -1;perror("rdma_reg_msgs for send_msg");goto out_dereg_recv;}}   ret = rdma_accept(id, NULL);if (ret) {perror("rdma_accept");goto out_dereg_send;}while (1) {memset(recv_msg, 0 , sizeof recv_msg);memset(send_msg, 0 , sizeof send_msg);ret = rdma_post_recv(id, NULL, recv_msg, MAX_CAP, mr);if (ret) {perror("rdma_post_recv");goto out_dereg_send;}while ((ret = rdma_get_recv_comp(id, &wc)) == 0);if (ret < 0) {perror("rdma_get_recv_comp");goto out_disconnect;}char *s = (char *)recv_msg;int total_length = strlen("server get ") + strlen(s); // 加1是为了存储字符串结束符'\0'char *recv_str = (char *)malloc(total_length);  // 分配足够的空间strcpy(recv_str, "server get ");strcat(recv_str, s);//printf("%s\n", recv_str);memcpy(send_msg, recv_str, strlen(recv_str));ret = rdma_post_send(id, NULL, send_msg, MAX_CAP, send_mr, send_flags);if (ret) {perror("rdma_post_send");goto out_disconnect;}if(strcmp((char*)recv_msg,"disconnect") == 0){//printf("%s\n",recv_msg);printf("client disconnect\n");rdma_disconnect(id);if ((send_flags & IBV_SEND_INLINE) == 0)rdma_dereg_mr(send_mr);rdma_dereg_mr(mr);rdma_destroy_ep(id);rdma_destroy_ep(listen_id);rdma_freeaddrinfo(res);  //goto out_disconnect;goto connect;}else{printf("%s\n", recv_msg);}// while ((ret = rdma_get_send_comp(id, &wc)) == 0); // 确认对方已经收到 对方发送ack// printf("after send\n");// if (ret < 0)//     perror("rdma_get_send_comp");// else//     ret = 0;}out_disconnect:rdma_disconnect(id);
out_dereg_send:if ((send_flags & IBV_SEND_INLINE) == 0)rdma_dereg_mr(send_mr);
out_dereg_recv:rdma_dereg_mr(mr);
out_destroy_accept_ep:rdma_destroy_ep(id);
out_destroy_listen_ep:rdma_destroy_ep(listen_id);
out_free_addrinfo:rdma_freeaddrinfo(res);  return ret;
}int main(int argc, char **argv)
{int op, ret;while ((op = getopt(argc, argv, "s:p:")) != -1) {switch (op) {case 's':server = optarg;break;case 'p':port = optarg;break;default:printf("usage: %s\n", argv[0]);printf("\t[-s server_address]\n");printf("\t[-p port_number]\n");exit(1);}}printf("rdma_server: start\n");ret = run();printf("rdma_server: end %d\n", ret);return ret;
}

运行结果:

在这里插入图片描述
在这里插入图片描述

总结:

本文实现了rdma中send-receive双边原语的三种需求版本,从单次发送到两者都能多次发送。理解其中的代码逻辑,想要发送消息之前对端得创建一个recv队列用来接收消息。发送完了有一个发送完成队列,接收完了也有一个接收完成队列。最后双方断开连接需要一起断开,不能某一方执行disconnect另一方不执行。本次实验有一个关键点:

while ((ret = rdma_get_send_comp(id, &wc)) == 0)

这一行代码是等待发送成功,发送成功之后,对方会给一个隐式信息表示我已经收到。这里耗费得时间比较长一点,在版本3中,如果不注释掉,在server端的receive队列还没有建立好,这就导致client发送了消息,server还没有收到,双方就陷入了死循环中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/241636.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 【C编程】 引入线程,线程相关函数

1.线程的引入 1.1使用线程同时读取键盘和鼠标 代码演示&#xff1a; #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <termios.h> #include <fcntl.h> #include <string.h> // 读取…

鸿蒙HarmonyOS实战-ArkTS语言(基本语法)

&#x1f680;一、ArkTS语言基本语法 &#x1f50e;1.简介 HarmonyOS的ArkTS语言是一种基于TypeScript开发的语言&#xff0c;它专为HarmonyOS系统开发而设计。ArkTS语言结合了JavaScript的灵活性和TypeScript的严谨性&#xff0c;使得开发者能够快速、高效地开发出高质量的Har…

如何从命令行运行testng.xml?

目录 创建一个新的java项目并从命令行运行testng.xml 使用命令行运行XML文件 从命令行运行现有maven项目的XML文件 在这篇文章中&#xff0c;我们将使用命令行运行testng.xml。有多种场景需要使用命令行工具运行testng.xml。也许您已经创建了一个maven项目&#xff0c;现在想…

git提交代码到远端仓库的方法详解

一、何为git git就是版本控制器&#xff0c;就比如说你新建了一个git文件夹&#xff0c;里面用于存放你的C语言实习报告&#xff0c;现在要用git对该文件夹进行接管。当你修改了你的C语言实习报告点击保存之后&#xff0c;就用git的相关命令&#xff0c;提交给git&#xff0c;让…

Flask 3.x log全域配置(包含pytest)

最近使用到flask3.x&#xff0c;配置了全域的log&#xff0c;这边记录下 首先需要创建logging的配置文件&#xff0c;我是放在项目根目录的&#xff0c; Logging 配置 logging.json {"version": 1, # 配置文件版本号"formatters": {"default&qu…

git中合并分支时出现了代码冲突怎么办

目录 第一章、Git代码冲突介绍1.1&#xff09;什么是Git代码冲突①git merge命令介绍②代码冲突原因 1.2&#xff09;提示代码冲突的两种情况①本地不同分支的文件有差异时&#xff1a;②本地仓库和git远程仓库的文件有差异时&#xff1a; 1.3&#xff09;解决合并时的代码冲突…

音乐人声分离工具:极简的人声和背景音乐分离工具

这是一个极简的人声和背景音乐分离工具&#xff0c;本地化网页操作&#xff0c;无需连接外网&#xff0c;使用 2stems/4stems/5stems 模型。 将一首歌曲或者含有背景音乐的音视频文件&#xff0c;拖拽到本地网页中&#xff0c;即可将其中的人声和音乐声分离为单独的音频wav文件…

04 SpringBoot整合Druid/MyBatis/事务/AOP+打包项目

整合Druid 项目结构&#xff1a; 引入依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaL…

rust跟我学六:虚拟机检测

图为RUST吉祥物 大家好,我是get_local_info作者带剑书生,这里用一篇文章讲解get_local_info是怎么检测是否在虚拟机里运行的。 首先,先要了解get_local_info是什么? get_local_info是一个获取linux系统信息的rust三方库,并提供一些常用功能,目前版本0.2.4。详细介绍地址:…

00-Rust前言

问&#xff1a;为什么要近期想学习Rust? 答&#xff1a; Rust出来也是有一段时间了&#xff0c;从Microsoft吵着要重构他们的C"祖传代码"开始&#xff0c;Rust就披着“高效&#xff0c;安全”的头衔。而自己决定要学习Rust&#xff0c;是因为近期发现&#xff1a;与…

TDengine 企业级功能:存储引擎对多表低频场景优化工作分享

在去年 8 月份发布的 3.1.0.0 版本中&#xff0c;TDengine 进行了一系列重要的企业级功能更新&#xff0c;其中包括对多表低频场景写入性能的大幅优化。这一优化工作为有此需求的用户提供了更大的便捷性和易用性。在本文中&#xff0c;TDengine 的资深研发将对此次优化工作进行…

Java项目:10 Springboot的电商书城管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 该系统分为前台展示和后台管理两大模块&#xff0c;前台主要是为消费者服务。该子系统实现了注册&#xff0c;登录&#xff0c;以及从浏览、下…

强化学习(二)多臂老虎机 “Multi-armed Bandits”——1

将强化学习与机器学习、深度学习区分开的最重要的特征为&#xff1a;它通过训练中信息来评估所采取的动作&#xff0c;而不是给出正确的动作进行指导&#xff0c;这极大地促进了寻找更优动作的需求。 1、多臂老虎机&#xff08;Multi-armed Bandits&#xff09;问题 赌场的老虎…

JS遍历对象的方法及特点

1、定义一个对象 let obj {name: Tom,age: 20,sex: 男,};obj.weight 70kg;// obj的原型上定义属性Object.prototype.height 180cm;Object.prototype.major function() {console.log(专业&#xff1a;计算机应用技术);};console.log(obj, obj); 控制台输出的obj中&#xff…

c++:基于c语言基础上的语法不同(1)

前言&#xff1a;此篇文章适合学完c语言基础概念的同学&#xff0c;是帮助c向c语言的同学快速掌握基本语法。 基础格式 #include<iostream>using namespace std; int main() {system("pause");return 0; } 输入&#xff1a; cin>>a;//a是输入内容 输出…

最新ChatGPT/GPT4科研应用与AI绘图及论文高效写作

详情点击链接&#xff1a;最新ChatGPT/GPT4科研应用与AI绘图及论文高效写作 一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型Clau…

如何手写一个RPC?

在学习 RPC 框架之前&#xff0c;我们先来手写一个RPC。 我们在学习的过程中&#xff0c;一定要做到知其然&#xff0c;还要知其所以然。 架构演进 单体架构 要知道&#xff0c;在以前单体架构的时候&#xff0c;会将所有的应用功能都集中在一个服务当中。 单体架构初始开发…

傲空间私有部署 Linux 指南

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 安装 docker 请下载对应的 Docker&#xff0c;安装完成后启动。Install Docker Engine on Ubu…

开发实践5_project

要求&#xff1a; &#xff08;对作业要求的"Student"稍作了变换&#xff0c;表单名称为“Index”。&#xff09;获得后台 Index 数据&#xff0c;作展示&#xff0c;要求使用分页器&#xff0c;包含上一页、下一页、当前页/总页。 结果&#xff1a; ① preparatio…

软件测试|sqlalchemy一对一关系详解

简介 SQLAlchemy 是一个强大的 Python ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它允许我们将数据库表映射到 Python 对象&#xff0c;并提供了丰富的关系模型来处理不同类型的关系&#xff0c;包括一对一关系。在本文中&#xff0c;我们将深入探讨 SQLAlchemy …