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.mzph.cn/news/634757.shtml

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

相关文章

Javaweb之SpringBootWeb案例员工管理之删除员工的详细解析

3.3 删除员工 查询员完成之后&#xff0c;我们继续开发新的功能&#xff1a;删除员工。 3.3.1 需求 当我们勾选列表前面的复选框&#xff0c;然后点击 "批量删除" 按钮&#xff0c;就可以将这一批次的员工信息删除掉了。也可以只勾选一个复选框&#xff0c;仅删除一…

超详细的 pytest 钩子函数 —— 之初始钩子和引导钩子来啦!

前几篇文章介绍了 pytest 点的基本使用&#xff0c;学完前面几篇的内容基本上就可以满足工作中编写用例和进行自动化测试的需求。从这篇文章开始会陆续给大家介绍 pytest 中的钩子函数&#xff0c;插件开发等等。 仔细去看过 pytest 文档的小伙伴&#xff0c;应该都有发现 pyt…

PSP - 提取 UniRef 数据库搜索的 MSA 序列物种 (Species) 信息

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/135702185 UniRef库&#xff1a;UniProt参考聚类&#xff08;UniRef&#xff09;的简称&#xff0c;提供了从UniProt知识库&#xff08;包括异构体…

[力扣 Hot100]Day7 接雨水

题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 出处 思路 就是寻找“凹”形区间&#xff0c;找使得左右两端点为最大的两个值的最长区间。这里我分了两种情况&#xff0c;右边大于等于左边…

MySQL深度分页优化问题

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

RenderDoc 增加 DXBC to HLSL 的 shader viewer

目的 便于后续抓帧出来的 DXBC 转为 HLSL&#xff0c;提高可读性 原因 编写的原因&#xff0c;因为按照网上的大佬的BLOG&#xff0c;发现某个 etnlGD/HLSLDecompiler 上的工具使用上是有问题的 &#xff08;有可能是以前的 render doc 版本没有问题&#xff0c;而我现在是在…

KubeSphere平台使用

KubeSphere官网地址&#xff1a;https://kubesphere.io/zh/ KubeKey一键部署K8S集群&#xff1a;https://kubesphere.io/zh/docs/v3.4/installing-on-linux/introduction/multioverview/ 一台master node&#xff08;初始化主节点&#xff09;、两台 work node&#xff08; joi…

SCI好看的配图-汇总

文章目录 图源&#xff1a;Sustainable Cities and Society【期刊】条形图2热力图-地图 图源&#xff1a;Sustainable Cities and Society【期刊】 引自&#xff1a;A machine learning-driven spatio-temporal vulnerability appraisal based on socio-economic data for COV…

如何编写一个好的测试用例?才能防止背黑锅

如何编写一个好的测试用例&#xff1f;才能防止背黑锅 什么是测试用例&#xff1f;一个好的测试用例包含什么&#xff1f;测试用例的编写思路总结 什么是测试用例&#xff1f; 在这之前&#xff0c;思考一个问题&#xff0c;下面这个简单的QQ登录页面&#xff0c;一共又多少条…

关于运维·关于Zabbix监控平台的面试点

目录 引言&#xff1a;明人不说暗话&#xff0c;今天分享几个在面试的时候常被问到关于Zabbix监控平台的面试点 1、zabbix的优点 2、zabbix的缺点 3、zabbix的监控模式 4、zabbix自定义监控怎么做 5、zabbix的自动发现功能 6、zabbix分布式监控有什么特点 引言&#xff1…

专业130+总分380+哈尔滨工程大学810信号与系统考研经验水声电子信息与通信

今年专业课810信号与系统130&#xff0c;总分380顺利考上哈尔滨工程大学&#xff0c;一年的努力终于换来最后的录取&#xff0c;期中复习有得有失&#xff0c;以下总结一下自己的复习经历&#xff0c;希望对大家有帮助&#xff0c;天道酬勤&#xff0c;加油&#xff01;专业课&…

入门设计者不容错过!5款网页原型设计工具推荐!

即时设计 即时设计是一种支持团队合作的原型设计工具&#xff0c;不限于设备和人群的使用&#xff0c;浏览器可以打开和使用。在即时设计中&#xff0c;您可以从0到1创建一个Web页面原型&#xff0c;具有钢笔、矩形、矢量编辑、轮廓、文本、色彩填充等设计功能&#xff0c;足以…

达梦数据库入门语法:从基础到进阶的指南

目录 博客前言&#xff1a; 达梦数据库语法介绍 一.创建表空间 1.图形化创建 2.语法创建 ​编辑​编辑 3.修改表空间参数 图形化修改 ​编辑​编辑 语法修改 4.设置加密算法、密码 二.创建用户 1.图形化 2.sql执行 ​编辑 3.授予权限 授予用户 DBA 权限 授予用户…

三、RHCE--时间服务器

三、RHCE--时间服务器 一、简介二、软件安装三、配置时间服务器客户端四、配置时间服务器服务端五、示例&#xff1a; 一、简介 NTP 是网络时间协议&#xff08;Network Time Protocol&#xff09;的简称&#xff0c;通过 udp 123 端口进行网络时钟同步。 Chrony是一个开源自由…

k8s---ingress对外服务(traefik)

目录 ingress的证书访问 traefik traefik的部署方式&#xff1a; deamonset deployment nginx-ingress与traefix-ingress相比较 nginx-ingress-controller ui访问 deployment部署 ingress的证书访问 ingress实现https代理访问: 需要证书和密钥 创建证书 密钥 secre…

将 SQL Server 2022 数据库备份到 MinIO

Microsoft 在将 S3 连接器和 Polybase 添加到 SQL Server 2022 时取得了重大飞跃。因此&#xff0c;企业可以利用他们保存到对象存储中的大量数据&#xff0c;并使用它来丰富 SQL Server 表。他们还可以利用对象存储来备份 SQL Server&#xff0c;这是开放性和云原生灵活性的又…

UE4 添加按键输入事件 并在蓝图中使用按键输入节点

绑定按键 选择Edit/ProjectSettings/Engine/Input 在bindings中可以选择添加ActionMappings或则AxisMappings ActionMappings:按键事件&#xff0c;有按下和抬起两个事件&#xff0c;需要分别用两个键触发AxisMappings:输入事件&#xff0c;返回值为float&#xff0c;对于键盘…

每日OJ题_算法_滑动窗口⑤_力扣904水果成篮

目录 力扣904. 水果成篮 解析及代码1&#xff08;使用容器&#xff09; 解析及代码2&#xff08;开数组&#xff09; 力扣904. 水果成篮 904. 水果成篮 - 力扣&#xff08;LeetCode&#xff09; 难度 中等 你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这…

Elastic Stack(1):Elastic Stack简介

1 简介 ELK是一个免费开源的日志分析架构技术栈总称&#xff0c;官网https://www.elastic.co/cn。包含三大基础组件&#xff0c;分别是Elasticsearch、Logstash、Kibana。但实际上ELK不仅仅适用于日志分析&#xff0c;它还可以支持其它任何数据搜索、分析和收集的场景&#xf…

GLM-4多模态重磅更新!摸着OpenAI过河!

智谱CEO张鹏说&#xff1a;OpenAI摸着石头过河&#xff0c;我们摸着OpenAI过河。 摸来摸去摸了一年&#xff0c;以每3-4个月升级一次基座模型的速度&#xff0c;智谱摸着OpenAI过河的最新成绩到底怎么样&#xff1f;真如所说吗&#xff1f; 听到GLM-4发布的当天&#xff0c;我就…