当前位置: 首页 > news >正文

Linux网络设计中的Reactor网络模型与百万级并发

结构说明:以fd作为索引,存放在block中;当一个fd到来时,通过fd/MAX先找到fd对应的block号,再通过fd%MAX找到对应的偏移地址。例如来了个fd=10000,每个块存放的最大item数量MAX=1024,那么fd对应的block序号等于10000/1024=9;偏移量等于10000%1024=784。这样就可以找到fd对应的数据存放地址item。

数据结构的代码实现如下:

代码语言:javascript

AI代码解释

struct ntyevnt{ int fd;//事件fd char buffer[BUFFER_LENGTH];//缓冲区 int length;//缓存长度 int status;//状态 int events;//事件 void *arg;//callback的参数 int(*callback)(int fd, int events, void* arg);//回调函数 }; struct eventblock{ struct *sock_items;//事件集合 struct eventblock *next;//指向下一个内存块 }; struct reactor{ int epfd;//epoll的文件描述符 int blkcnt;//事件块的数量 struct eventblock *evtblk;//事件块的起始地址 };

step 2:实现Reactor容器初始化功能

我们这里使用epoll作为IO多路复用器。 思路:初始化reactor内存块,避免脏数据;创建events和block并初始化,将events添加到block中,将block添加到reactor的链表中管理。

代码语言:javascript

AI代码解释

int ntyreactor_init(struct ntyreactor *reactor) { if (reactor == NULL) return -1; memset(reactor, 0, sizeof(struct ntyreactor)); //创建epoll,作为IO多路复用器 reactor->epfd = epoll_create(1); if (reactor->epfd <= 0) { printf("create epfd in %s error %s\n", __func__, strerror(errno)); return -2; } // 创建事件集 struct ntyevnt *events = (struct ntyevnt *)malloc(MAX_EPOLL_EVENTS * sizeof(struct ntyevnt)); if (events == NULL) { printf("create ntyevnt in %s error %s\n", __func__, strerror(errno)); close(reactor->epfd); return -3; } memset(events, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent)); //创建事件内存块 struct eventblock *block = (struct eventblock*)malloc(sizeof(struct eventblock)); if (block == NULL) { printf("create eventblock in %s error %s\n", __func__, strerror(errno)); free(events); close(reactor->epfd); return -4; } block->events = events; block->next = NULL; // reactor初始化赋值 reactor->evblks=block; reactor->blkcnt = 1; return 0; }

step 3:实现socket初始化功能

定义成一个函数,方便初始化多个监听端口。

代码语言:javascript

AI代码解释

int init_sock(short port) { int ret = 0; int fd = socket(AF_INET, SOCK_STREAM, 0);//创建套字接 if (fd == -1) { printf("create socket in %s error %s\n", __func__, strerror(errno)); return -1; } ret=fcntl(fd, F_SETFL, O_NONBLOCK);//设置非阻塞 if (ret == -1) { printf("fcntl O_NONBLOCK in %s error %s\n", __func__, strerror(errno)); return -1; } // 设置属性 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET;// IPV4 server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(port); // 绑定 ret = bind(fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (ret == -1) { printf("bind() in %s error %s\n", __func__, strerror(errno)); return -1; } //监听 ret = listen(fd, 20); if (ret < 0) { printf("listen failed : %s\n", strerror(errno)); return -1; } printf("listen server port : %d\n", port); return fd; }

step 4:实现Reactor动态扩容功能

为了实现高并发,服务器需要监听多个端口。当高并发时需要reactor容器进行扩容管理。 核心思路:找到链表的末端,分别为events和block分配内存并初始化,将events添加到block中,将block添加到reactor的链表中管理。

代码语言:javascript

AI代码解释

int ntyreactor_alloc(struct ntyreactor *reactor) { if (reactor == NULL) return -1; if (reactor->evblks == NULL) return -1; //找到链表末端 struct eventblock *blk = reactor->evblks; while (blk->next != NULL) blk = blk->next; // 创建事件集 struct ntyevent *evs = (struct ntyevent*)malloc((MAX_EPOLL_EVENTS) * sizeof(struct ntyevent)); if (evs == NULL) { printf("ntyreactor_alloc ntyevent failed\n"); return -2; } memset(evs, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent)); // 创建事件块 struct eventblock *block = (struct eventblock*)malloc(sizeof(struct eventblock)); if (block == NULL) { printf("ntyreactor_alloc eventblock failed\n"); return -3; } block->events = evs; block->next = NULL; //实现扩容 blk->next = block; reactor->blkcnt++; return 0; }

step 5:实现Reactor索引功能

思路:通过fd/MAX先找到fd对应的block号,再通过fd%MAX找到对应的偏移地址。 例如来了个fd=10000,每个块存放的最大item数量MAX=1024,那么fd对应的block序号等于10000/1024=9;偏移量等于10000%1024=784。这样就可以找到fd对应的数据存放地址item。

代码语言:javascript

AI代码解释

struct ntyevent *ntyreactor_idx(struct ntyreactor *reactor, int sockfd) { if (reactor == NULL) return NULL; if (reactor->evblks == NULL) return NULL; // fd所在block序号 int blkidx = sockfd / MAX_EPOLL_EVENTS; while (blkidx >= reactor->blkcnt) { // 扩容 ntyreactor_alloc(reactor); } //找到fd对应block的位置 int i = 0; struct eventblock *blk = reactor->evblks; while (i++ != blkidx && blk != NULL) { blk = blk->next; } // 返回item 地址 return &blk->events[sockfd%MAX_EPOLL_EVENTS]; }

step 6:实现设置事件信息功能

将事件的相关信息保存到数据结构中。主要实现填充关键信息到event结构体中。

代码语言:javascript

AI代码解释

void nty_event_set(struct ntyevent *ev,int fd,NCALLBACK callback,void *arg) { ev->fd = fd; ev->events = 0; ev->callback = callback; ev->arg = arg; }

step 7:实现IO事件监听功能

这里使用epoll作为IO多路复用器,将事件添加到epoll中监听。 思路:主要是epoll_ctl操作,将事件添加到reactor的event结构体中。

代码语言:javascript

AI代码解释

int nty_event_add(int epfd, int events, struct ntyevent *ev) { // 设置epoll事件信息 struct epoll_event ep_ev = { 0,{ 0} }; ep_ev.data.ptr = ev; ep_ev.events = ev->events = events; // 判断,设置epfd的操作模式 int op; if (ev->status == 1) op = EPOLL_CTL_MOD; else { op = EPOLL_CTL_ADD; ev->status = 1; } // 设置epoll int ret = epoll_ctl(epfd, op, ev->fd, &ep_ev); if (ret < 0) { printf("event add failed [fd=%d], events[%d],ret:%d\n", ev->fd, events,ret); printf("event add failed in %s error %s\n", __func__, strerror(errno)); return -1; } return 0; }

step 8:实现IO事件移除功能

由于设置了非阻塞模式,当事件到来时,需要暂时移除监听,避免干扰。

http://www.jsqmd.com/news/813743/

相关文章:

  • JIT只适合大厂?精益生产中小厂JIT落地技巧,不用大投入也能降库存!
  • CODEX 认知、学习、使用
  • 3步开启你的缠论交易导航:告别复杂画图,拥抱智能分析
  • 月薪2万+,2026年AI智能体工程师,这个岗位火了
  • 告别误区!一张图深度解析:Agent为何远超Tool Calling?
  • 3步掌握APK Installer:Windows系统轻量级安卓应用安装方案
  • 从接入到稳定运行Taotoken在延迟与容灾方面的实际体验
  • ASN.1 Editor:深度解析二进制数据可视化的专业工具
  • linux小进阶
  • Windows上的终极APK安装解决方案:3分钟快速安装安卓应用
  • 第69篇:Vibe Coding时代:LangGraph + 工作流灰度发布实战,解决新 Agent 流程上线后大面积翻车问题
  • MySQL一行记录是如何存储的?
  • AI抢走工作?别慌!这7大新职业正在崛起,高薪等你来拿!
  • TypeScript领域建模实战:基于斯坦福本体论七步法构建健壮数据模型
  • 智能汽车目标假车路径跟踪控制【附仿真】
  • OpenTron:基于Node.js的模块化Discord机器人开发框架详解
  • 突破内存墙:Google Gemma 4 如何通过推测解码实现 3 倍提速?
  • 终极指南:如何使用KMS_VL_ALL_AIO一键激活Windows和Office
  • AI代码质检员Codeffect:10个智能体自动审查与优化生成代码
  • Cursor Pro破解工具:如何彻底解决API限制并实现无限免费使用
  • Hysteria:极速抗审查代理工具,多模式跨平台优势尽显
  • 2026 简历制作平台推荐:5 款主流工具深度测评(含 AI 辅助、模板库及导出对比)
  • Python正则表达式详解(一)
  • 跨境电商OPC,掌握这几款产品,实现效率提升,欢迎评论交流
  • 毕业答辩 PPT 做了 3 天还被导师打回?okbiye AI PPT 一键搞定,我把流程和效果都给你测透了
  • DC-DC转换器技术解析与应用指南
  • 嵌入式Day14--函数指针与指针函数
  • 3步搞定视频硬字幕提取:本地化、多语言、高效率的终极解决方案
  • 尾盘选股法程序开发学习初期
  • 08:redis-实战+原理