C++基于reactor的服务器百万并发如何实现

本文详细介绍了如何使用C++基于reactor模式构建能处理百万并发的服务器,内容涵盖服务器代码实现、环境设置及系统限制的调整,如调整文件描述符限制和优化TCP内存及缓冲区大小,以实现高并发性能。
摘要由CSDN通过智能技术生成

这篇文章主要介绍“C++基于reactor的服务器百万并发如何实现”,在日常操作中,相信很多人在C++基于reactor的服务器百万并发如何实现问题上存在疑惑,狮查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++基于reactor的服务器百万并发如何实现”的疑惑有所帮助!接下来,请跟着狮一起来学习吧!

并发量和承载的概念
并发量:一个服务器能同时承载客户端的数量
承载:客户端发送给服务器的请求(http或tcp等)在200ms内可以返回正确的结果

一、服务器的代码实现与讲解

结构体代码主要构建的结构如图所示
链表结构,每个eventblock结点,包括一个ntyevent数组,数组中存储fd

/*结构体定义链表数组*/
struct ntyevent {
	int fd;//要监听的文件描述符
	int events;//对应的监听事件,	EPOLLIN和EPOLLOUT(不同的事件,走不同的回调函数)
	void *arg;//指向自己结构体指针
	int (*callback)(int fd, int events, void *arg);
	
	int status;//是否在监听:1->在红黑树上(监听),0->不在(不监听)
	char buffer[BUFFER_LENGTH];
	int length;
	long last_active;
};

struct eventblock {

	struct eventblock *next;
	struct ntyevent *events;//数组
	
};

struct ntyreactor {
	//句柄
	int epfd;
	//结点个数
	int blkcnt;
	struct eventblock *evblk; //fd --> 100w
};

初始化fd 上树、下树代码

//nty_event_set(event, sockfd, acceptor, reactor);
//初始化sockfd
void nty_event_set(struct ntyevent *ev, int fd, NCALLBACK callback, void *arg) {

	ev->fd = fd;
	ev->callback = callback;
	ev->events = 0;
	ev->arg = arg;
	ev->last_active = time(NULL);

	return ;
	
}
//nty_event_add(reactor->epfd, EPOLLIN, event);
//对监听的epoll红黑树上的结点的修改
int nty_event_add(int epfd, int events, struct ntyevent *ev) {

	struct epoll_event ep_ev = {0, {0}};
	ep_ev.data.ptr = ev;
	ep_ev.events = ev->events = events;

	int op;
	if (ev->status == 1) {
		op = EPOLL_CTL_MOD;
	} else {
		op = EPOLL_CTL_ADD;
		ev->status = 1;
	}

	if (epoll_ctl(epfd, op, ev->fd, &ep_ev) < 0) {
		printf("event add failed [fd=%d], events[%d]\n", ev->fd, events);
		return -1;
	}

	return 0;
}

int nty_event_del(int epfd, struct ntyevent *ev) {

	struct epoll_event ep_ev = {0, {0}};

	if (ev->status != 1) {
		return -1;
	}
	ep_ev.data.ptr = ev;
	ev->status = 0;
	epoll_ctl(epfd, EPOLL_CTL_DEL, ev->fd, &ep_ev);

	return 0;
}

回调函数代码的书写
注意看recv_cb的回调函数中,recv之后,立马下树,然后又重新初始化fd,上树。这样做的目的是因为代码逻辑是recv收到数据后,立即原样send,所以需要对fd的属性进行更改,需要重新初始化赋值,然后上树

int recv_cb(int fd, int events, void *arg) {

	struct ntyreactor *reactor = (struct ntyreactor*)arg;
	struct ntyevent *ev = ntyreactor_idx(reactor, fd);

	int len = recv(fd, ev->buffer, BUFFER_LENGTH , 0); // 
	nty_event_del(reactor->epfd, ev);

	if (len > 0) {
		
		ev->length = len;
		ev->buffer[len] = '\0';

		printf("C[%d]:%s\n", fd, ev->buffer);

		nty_event_set(ev, fd, send_cb, reactor);
		nty_event_add(reactor->epfd, EPOLLOUT, ev);
		
		
	} else if (len == 0) {

		close(ev->fd);
		//printf("[fd=%d] pos[%ld], closed\n", fd, ev-reactor->events);
		 
	} else {

		close(ev->fd);
		printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
		
	}

	return len;
}

int send_cb(int fd, int events, void *arg) {

	struct ntyreactor *reactor = (struct ntyreactor*)arg;
	struct ntyevent *ev = ntyreactor_idx(reactor, fd);

	int len = send(fd, ev->buffer, ev->length, 0);
	if (len > 0) {
		printf("send[fd=%d], [%d]%s\n", fd, len, ev->buffer);

		nty_event_del(reactor->epfd, ev);
		nty_event_set(ev, fd, recv_cb, reactor);
		nty_event_add(reactor->epfd, EPOLLIN, ev);
		
	} else {

		close(ev->fd);

		nty_event_del(reactor->epfd, ev);
		printf("send[fd=%d] error %s\n", fd, strerror(errno));

	}

	return len;
}

int accept_cb(int fd, int events, void *arg) {

	struct ntyreactor *reactor = (struct ntyreactor*)arg;
	if (reactor == NULL) return -1;

	struct sockaddr_in client_addr;
	socklen_t len = sizeof(client_addr);

	int clientfd;

	if ((clientfd = accept(fd, (struct sockaddr*)&client_addr, &len)) == -1) {
		if (errno != EAGAIN && errno != EINTR) {
			
		}
		printf("accept: %s\n", strerror(errno));
		return -1;
	}
	int flag = 0;
	if ((flag = fcntl(clientfd, F_SETFL, O_NONBLOCK)) < 0) {
		printf("%s: fcntl nonblocking failed, %d\n", __func__, MAX_EPOLL_EVENTS);
		return -1;
	}
	/*存储*/
	struct ntyevent *event = ntyreactor_idx(reactor, clientfd);
	
	nty_eve
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值