c/c++后台开发学习笔记 2.1.2 reactor原理与实现,实现百万级并发

本文介绍了C/C++中Reactor模式的原理与实现,通过封装epoll事件并设置回调函数,实现对百万级并发的支持。文章详细讲解了如何使用Reactor处理fd的读写事件,以及如何处理水平触发和边沿触发。同时,还提到了达到高并发所需的系统配置调整,如增加最大打开文件数和调整TCP缓存大小。
摘要由CSDN通过智能技术生成

reactor

把epoll返回的fd读写事件进行封装,并为每种事件设置回调函数,把所有关注的fd以及对应的事件存储在一个数据结构里,与epoll内部的红黑树的节点形成一一对应的关系。epoll返回时使用data.ptr得到我们数据结构中对应的entry,再进行处理
对fd的封装如下

typedef int (*NCALLBACK)(int fd, int events, void *arg);

struct ntyevent {
   
	int fd;
	int events;                     //监听的事件:EPOLLIN或EPOLLOUT
	void *arg;                      //传给回调函数的额外参数(reactor指针)
	NCALLBACK callback;             //回调函数
	
	int used;                       //当前entry是有有效
	char buffer[BUFFER_LENGTH];     //读写共用一个buffer,因为当前监听的事件只能是读或写,不会两个都有
	int length;                     //buffer中有效数据的长度
	long last_active;               //当前fd上一次活跃的事件
	int sticky;                     //如果置为1,则fd不会因为长时间不活跃而被关闭(用于listenfd)
};

reactor数据结构的定义如下

struct ntyreactor {
   
	int epfd;
	int block_num;
	struct ntyevent **events; //array of ntyevent *, length = block_num, each block has 1024 ntyevent
};

events是一个指针数组,可扩容。每个元素指向一个1024长度的ntyevent数组

整个服务器大致有如下函数


int accept_cb(int fd, int events, void *arg);
int recv_cb(int fd, int events, void *arg);
int send_cb(int fd, int events, void *arg);

void nty_event_update(struct ntyevent *ev, int fd, NCALLBACK callback, void *arg);
int nty_event_add(int epfd, int events, struct ntyevent *ev);
int nty_event_del(int epfd, struct ntyevent *ev);

int start_listen(short port);
int ntyreactor_init(struct ntyreactor *reactor);
struct ntyevent *ntyreactor_get_event(struct ntyreactor *reactor, int fd);
int ntyreactor_destory(struct ntyreactor *reactor);
int ntyreactor_addlistener(struct ntyreactor *reactor, int listenfd, NCALLBACK acceptor);
int ntyreactor_run(struct ntyreactor *reactor);

先看main函数

#define BUFFER_LENGTH		4096
#define EVENTS_BLOCK_SIZE	1024
#define EVENT_BATCH_SIZE    1024
#define SERVER_PORT			8888
#define PORT_COUNT          100
#define CLIENT_TIMEOUT      15

int main(int argc, char *argv[]) {
   

	unsigned short port = SERVER_PORT;
	if (argc == 2) {
   
		port = atoi(argv[1]);
	}

	struct ntyreactor *reactor = (struct ntyreactor*)calloc(1, sizeof(struct ntyreactor));
	ntyreactor_init(reactor);
	
	int i;
	for(i = 0; i < PORT_COUNT; i++) {
   
		int listenfd = start_listen(port + i);
		ntyreactor_addlistener(reactor, listenfd, accept_cb);
	}
	ntyreactor_run(reactor);

	ntyreactor_destory(reactor);
	free(reactor);
	return 0;
}

PORT_COUNT设为100时,程序监听从8888开始的100个端口,每个端口至少能接受1万个port,所以连接数能达到一百万。(因为测试的客户端数量比较少,如果不多监听一些端口,会导致(src-ip, src-port, dst-ip, dst-port) 四元组的数量不够用)

其中ntyreactor_run是程序主循环

int ntyreactor_run(struct ntyreactor *reactor) {
   
	if (reactor == NULL) return -1;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值