0
点赞
收藏
分享

微信扫一扫

rdma-core之rcopy.c

库文件、结构体和全局变量

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <getopt.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>

#include <rdma/rsocket.h>

#include "common.h"

union rsocket_address {
	struct sockaddr		sa;
	struct sockaddr_in	sin;
	struct sockaddr_in6	sin6;
	struct sockaddr_storage storage;
};
// 这些都是通信要使用的配置信息
static const char *port = "7427";
static char *dst_addr;
// 
static char *dst_file;
static char *src_file;

static struct timeval start, end;
//static void buf[1024 * 1024];
static uint64_t bytes;
static int fd;
static void *file_addr;

enum {
	CMD_NOOP,
	CMD_OPEN,
	CMD_CLOSE,
	CMD_WRITE,
	CMD_RESP = 0x80,
};

/* TODO: handle byte swapping */
struct msg_hdr {
	uint8_t  version;
	uint8_t  command;
	uint16_t len;
	uint32_t data;
	uint64_t id;
};

struct msg_open {
	struct msg_hdr hdr;
	char path[0];
};

struct msg_write {
	struct msg_hdr hdr;
	uint64_t size;
};

main函数

分析代码的主入口,可以看到首先是参数分析,根据参数的情况选择server_run或者是client_run。


int main(int argc, char **argv)
{
	int ret;

	if (argc == 1 || argv[1][0] == '-') {
		server_opts(argc, argv);
		ret = server_run();
	} else {
		client_opts(argc, argv);
		ret = client_run();
	}

	return ret;
}

client_run函数



static int client_run(void)
{
	struct msg_hdr ack;
	int ret, rs;
	size_t len;

	rs = client_connect(); // 建立连接,通过rsocket的方式
	if (rs < 0)
		return rs;

	ret = client_open(rs); // 发送数据过去
	if (ret)
		goto shutdown;

	ret = client_start_write(rs); // 开始发送数据。
	if (ret)
		goto close;

	printf("...");
	fflush(NULL);
	gettimeofday(&start, NULL);
	len = rsend(rs, file_addr, bytes, 0); //发送数据,源地址是file_addr,大小是bytes。
	if (len == bytes)
		ret = msg_get_resp(rs, &ack, CMD_WRITE); // 获取相应信息,提取数据到ack里面
	else
		ret = (int) len;

	gettimeofday(&end, NULL);

close:
	client_close(rs);
shutdown:
	rshutdown(rs, SHUT_RDWR);
	rclose(rs);
	if (!ret)
		show_perf();
	return ret;
}

client_open函数

主要是打开文件,然后发送数据到dst_file里面,然后判断发送的数据长度,然后判断返回的类型是否是CMD_RESP。


static int client_open(int rs)
{
	struct msg_open *msg; // 里面包含了一个柔性数组和一个msg_hdr信息
	struct stat stats;
	uint32_t len;
	int ret;

	printf("opening...");
	fflush(NULL);
	fd = open(src_file, O_RDONLY);
	if (fd < 0)
		return fd;

	ret = fstat(fd, &stats); // 这个是一个系统调用,把fd的信息存储在stats
	if (ret < 0)
		goto err1;

	bytes = (uint64_t) stats.st_size; // fd文件的实际数据的大小
	file_addr = mmap(NULL, bytes, PROT_READ, MAP_SHARED, fd, 0); // 做一个内存映射mmap
	if (file_addr == (void *) -1) {
		ret = errno;
		goto err1;
	}

	len = (((uint32_t) strlen(dst_file)) + 8) & 0xFFFFFFF8;
	msg = calloc(1, sizeof(*msg) + len);
	if (!msg) {
		ret = -1;
		goto err2;
	}

	msg->hdr.command = CMD_OPEN;
	msg->hdr.len = sizeof(*msg) + len;
	msg->hdr.data = (uint32_t) stats.st_mode; // 文件的访问权限
	strcpy(msg->path, dst_file); // 这个是把里面的内容拷贝到dst_file文件里面
	ret = rsend(rs, msg, msg->hdr.len, 0); // 发送msg地址,长度为msg->hdr.len这么大
	if (ret != msg->hdr.len)
		goto err3;

	ret = msg_get_resp(rs, &msg->hdr, CMD_OPEN); // 获取返回的信息,通过获取头部信息,判断长度和command是否是等于CMD_RESP。
	if (ret)
		goto err3;

	return 0;

err3:
	free(msg);
err2:
	munmap(file_addr, bytes);
err1:
	close(fd);
	return ret;
}

server_run函数

服务器的代码执行入口,首先server_listen函数,内部具体做了创建rsocket,然后设置rsocket属性,然后绑定源地址,然后开始rlisten监听连接。

然后进入一个死循环处理请求连接,raccepte函数,然后打印client的地址信息,然后开启一个新的server_process函数处理这个请求。后面就是关闭。


static int server_run(void)
{
	int lrs, rs;
	union rsocket_address rsa;
	socklen_t len;

	lrs = server_listen();
	if (lrs < 0)
		return lrs;

	while (1) {
		len = sizeof rsa;
		printf("waiting for connection...");
		fflush(NULL);
		rs = raccept(lrs, &rsa.sa, &len);

		printf("client: %s\n", _ntop(&rsa));
		server_process(rs);

		rshutdown(rs, SHUT_RDWR);
		rclose(rs);
	}
	return 0;
}

server_process函数

从rs里面获取一个msg信息,然后读取命令信息,最后根据不同的事件进行不同的处理。


static void server_process(int rs)
{
	struct msg_hdr msg;
	int ret;

	do {
		ret = msg_recv_hdr(rs, &msg);
		if (ret != sizeof msg)
			break;

		switch (msg.command) {
		case CMD_OPEN:
			ret = server_open(rs, &msg);
			break;
		case CMD_CLOSE:
			server_close(rs, &msg);
			ret = 0;
			break;
		case CMD_WRITE:
			ret = server_write(rs, &msg);
			break;
		default:
			msg_send_resp(rs, &msg, EINVAL);
			ret = -1;
			break;
		}

	} while (!ret);
}

举报

相关推荐

0 条评论