对于redis框架的理解(三)
上一篇讲完了initServer的大体流程,其中aeCreateEventLoop(),这个函数
没有详细说明,我们在这一篇里讲述Ae.h和Ae.c, 这里面的api阐述了如何创建
eventLoop和添加文件读写事件等等。
ae.h中的解释
- //文件读写事件回调函数
- typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
- //定时器回调函数
- typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
- //事件结束回调函数,析构一些资源
- typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData);
- //不是很清楚,应该是进程结束前做的回调函数
- typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop);
- //文件事件回调函数
- typedef struct aeFileEvent {
- int mask; /* one of AE_(READABLE|WRITABLE) */ //文件事件类型 读/写
- aeFileProc *rfileProc;
- aeFileProc *wfileProc;
- void *clientData;
- } aeFileEvent;
- /* A fired event */
- typedef struct aeFiredEvent {
- int fd; ////已出现的事件的文件号对应的事件描述在aeEventLoop.events[]中的下标
- int mask; //文件事件类型 AE_WRITABLE||AE_READABLE
- } aeFiredEvent;
- typedef struct aeTimeEvent {
- long long id; /* time event identifier. */ //由aeEventLoop.timeEventNextId进行管理
- long when_sec; /* seconds */
- long when_ms; /* milliseconds */
- aeTimeProc *timeProc;
- aeEventFinalizerProc *finalizerProc;
- void *clientData;
- struct aeTimeEvent *next;
- } aeTimeEvent;
- /* State of an event based program */
- typedef struct aeEventLoop {
- int maxfd; //监听的最大文件号
- int setsize; //跟踪的文件描述符最大数量
- long long timeEventNextId; //定时器事件的ID编号管理(分配ID号所用)
- time_t lastTime; /* Used to detect system clock skew */
- aeFileEvent *events; //注册的文件事件,这些是需要进程关注的文件
- aeFiredEvent *fired; //poll结果,待处理的文件事件的文件号和事件类型
- aeTimeEvent *timeEventHead; //定时器时间链表
- int stop; //时间轮询是否结束?
- void *apidata; //polling API 特殊的数据
- aeBeforeSleepProc *beforesleep; //休眠前的程序
- } aeEventLoop;
- /* Prototypes */
- //创建eventLoop结构
- aeEventLoop *aeCreateEventLoop(int setsize);
- //删除eventloop
- void aeDeleteEventLoop(aeEventLoop *eventLoop);
- //事件派发停止
- void aeStop(aeEventLoop *eventLoop);
- //添加文件读写事件
- int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
- aeFileProc *proc, void *clientData);
- //删除文件读写事件
- void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask);
- //获取文件事件对应类型(读或写)
- int aeGetFileEvents(aeEventLoop *eventLoop, int fd);
- //创建定时器事件
- long long aeCreateTimeEvent(aeEventLoop *eventLoop,
- long long milliseconds,aeTimeProc *proc, void *clientData,
- aeEventFinalizerProc *finalizerProc);
- //删除定时器事件
- int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id);
- //派发事件
- int aeProcessEvents(aeEventLoop *eventLoop, int flags);
- //等待millionseconds直到文件描述符可读或者可写
- int aeWait(int fd, int mask, long long milliseconds);
- //ae事件轮询主函数
- void aeMain(aeEventLoop *eventLoop);
- //获取当前网络模型
- char *aeGetApiName(void);
- //进程休眠前回调函数
- void aeSetBeforeSleepProc(aeEventLoop *eventLoop,
- aeBeforeSleepProc *beforesleep);
- //获取eventloop所有的事件个数
- int aeGetSetSize(aeEventLoop *eventLoop);
- //重新设置eventloop事件个数
- int aeResizeSetSize(aeEventLoop *eventLoop, int setsize);
ae.cpp中,一个函数一个函数解析
- //定义了几个宏,根据不同的宏加载
- //不同的网络模型
- #ifdef HAVE_EVPORT
- #include "ae_evport.c"
- #else
- #ifdef HAVE_EPOLL
- #include "ae_epoll.c"
- #else
- #ifdef HAVE_KQUEUE
- #include "ae_kqueue.c"
- #else
- #include "ae_select.c"
- #endif
- #endif
- #endif
aeCreateEventLoop,主要负责eventloop结构的创建和初始化,以及模型的初始化
- aeEventLoop *aeCreateEventLoop(int setsize) {
- aeEventLoop *eventLoop;
- int i;
- //创建eventloop
- if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) goto err;
- //为进程要注册的文件开辟空间
- eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);
- //为激活的要处理的文件开辟空间
- eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
- //开辟失败报错
- if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err;
- //设置监听事件总数
- eventLoop->setsize = setsize;
- //更新为当前时间
- eventLoop->lastTime = time(NULL);
- eventLoop->timeEventHead = NULL;
- eventLoop->timeEventNextId = ;
- eventLoop->stop = ;
- eventLoop->maxfd = -;
- eventLoop->beforesleep = NULL;
- //将不同模式的api注册到eventloop里
- if (aeApiCreate(eventLoop) == -) goto err;
- /* Events with mask == AE_NONE are not set. So let's initialize the
- * vector with it. */
- for (i = ; i < setsize; i++)
- //将所有文件事件类型初始为空
- eventLoop->events[i].mask = AE_NONE;
- return eventLoop;
- err:
- if (eventLoop) {
- zfree(eventLoop->events);
- zfree(eventLoop->fired);
- zfree(eventLoop);
- }
- return NULL;
- }
//事件队列大小和重置
- //获取eventloop事件队列大小
- int aeGetSetSize(aeEventLoop *eventLoop) {
- return eventLoop->setsize;
- }
- //重新设置大小
- int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) {
- int i;
- if (setsize == eventLoop->setsize) return AE_OK;
- if (eventLoop->maxfd >= setsize) return AE_ERR;
- //不同的网络模型调用不同的resize
- if (aeApiResize(eventLoop,setsize) == -) return AE_ERR;
- //重新开辟空间
- eventLoop->events = zrealloc(eventLoop->events,sizeof(aeFileEvent)*setsize);
- eventLoop->fired = zrealloc(eventLoop->fired,sizeof(aeFiredEvent)*setsize);
- eventLoop->setsize = setsize;
- /* Make sure that if we created new slots, they are initialized with
- * an AE_NONE mask. */
- //重新初始化事件类型
- for (i = eventLoop->maxfd+; i < setsize; i++)
- eventLoop->events[i].mask = AE_NONE;
- return AE_OK;
- }
删除eventloop和stop事件轮询
- //删除eventloop结构
- void aeDeleteEventLoop(aeEventLoop *eventLoop) {
- aeApiFree(eventLoop);
- zfree(eventLoop->events);
- zfree(eventLoop->fired);
- zfree(eventLoop);
- }
- //设置eventloop停止标记
- void aeStop(aeEventLoop *eventLoop) {
- eventLoop->stop = ;
- }
创建监听事件
- //创建监听事件
- int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
- aeFileProc *proc, void *clientData)
- {
- //判断fd大于eventloop设置的事件队列大小
- if (fd >= eventLoop->setsize) {
- errno = ERANGE;
- return AE_ERR;
- }
- //取出对应的aeFileEvent事件
- aeFileEvent *fe = &eventLoop->events[fd];
- //添加读写事件到不同的模型
- if (aeApiAddEvent(eventLoop, fd, mask) == -)
- return AE_ERR;
- //文件类型按位或
- fe->mask |= mask;
- //根据最终的类型设置读写回调函数
- if (mask & AE_READABLE) fe->rfileProc = proc;
- if (mask & AE_WRITABLE) fe->wfileProc = proc;
- //fe中读写操作的clientdata
- fe->clientData = clientData;
- //如果fd大于当前最大的eventLoop maxfdfd
- if (fd > eventLoop->maxfd)
- eventLoop->maxfd = fd;
- return AE_OK;
- }
删除监听事件
- void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
- {
- if (fd >= eventLoop->setsize) return;
- aeFileEvent *fe = &eventLoop->events[fd];
- if (fe->mask == AE_NONE) return;
- //网络模型里删除对应的事件
- aeApiDelEvent(eventLoop, fd, mask);
- //清除对应的类型标记
- fe->mask = fe->mask & (~mask);
- //如果删除的fd是maxfd,并且对应的事件为空,那么更新maxfd
- if (fd == eventLoop->maxfd && fe->mask == AE_NONE) {
- /* Update the max fd */
- int j;
- for (j = eventLoop->maxfd-; j >= ; j--)
- if (eventLoop->events[j].mask != AE_NONE) break;
- eventLoop->maxfd = j;
- }
- }
- //获取文件类型
- int aeGetFileEvents(aeEventLoop *eventLoop, int fd) {
- if (fd >= eventLoop->setsize) return ;
- aeFileEvent *fe = &eventLoop->events[fd];
- //返回对应的类型标记
- return fe->mask;
- }
事件派发函数
- //派发事件的函数
- int aeProcessEvents(aeEventLoop *eventLoop, int flags)
- {
- int processed = , numevents;
- /* Nothing to do? return ASAP */
- if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return ;
- //为了休眠,直到有时间事件触发,即便是没有文件事件处理,我们也会
- //调用对应的事件时间
- //这部分不是很清楚,知道大体意思是设置时间,
- //为了aeApiPoll设置等待的时间
- if (eventLoop->maxfd != - ||
- ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
- int j;
- aeTimeEvent *shortest = NULL;
- struct timeval tv, *tvp;
- if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
- shortest = aeSearchNearestTimer(eventLoop);
- if (shortest) {
- long now_sec, now_ms;
- /* Calculate the time missing for the nearest
- * timer to fire. */
- aeGetTime(&now_sec, &now_ms);
- tvp = &tv;
- tvp->tv_sec = shortest->when_sec - now_sec;
- if (shortest->when_ms < now_ms) {
- tvp->tv_usec = ((shortest->when_ms+) - now_ms)*;
- tvp->tv_sec --;
- } else {
- tvp->tv_usec = (shortest->when_ms - now_ms)*;
- }
- if (tvp->tv_sec < ) tvp->tv_sec = ;
- if (tvp->tv_usec < ) tvp->tv_usec = ;
- } else {
- /* If we have to check for events but need to return
- * ASAP because of AE_DONT_WAIT we need to set the timeout
- * to zero */
- if (flags & AE_DONT_WAIT) {
- tv.tv_sec = tv.tv_usec = ;
- tvp = &tv;
- } else {
- /* Otherwise we can block */
- tvp = NULL; /* wait forever */
- }
- }
- //调用不同的网络模型poll事件
- numevents = aeApiPoll(eventLoop, tvp);
- for (j = ; j < numevents; j++) {
- //轮询处理就绪事件
- aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
- int mask = eventLoop->fired[j].mask;
- int fd = eventLoop->fired[j].fd;
- int rfired = ;
- //可读就绪事件
- if (fe->mask & mask & AE_READABLE) {
- rfired = ;
- fe->rfileProc(eventLoop,fd,fe->clientData,mask);
- }
- //可写就绪事件
- if (fe->mask & mask & AE_WRITABLE) {
- if (!rfired || fe->wfileProc != fe->rfileProc)
- fe->wfileProc(eventLoop,fd,fe->clientData,mask);
- }
- processed++;
- }
- }
- /* Check time events */
- //处理所有定时器事件
- if (flags & AE_TIME_EVENTS)
- processed += processTimeEvents(eventLoop);
- return processed; /* return the number of processed file/time events */
- }
- /等待millionseconds,直到有可读或者可写事件触发
- int aeWait(int fd, int mask, long long milliseconds) {
- struct pollfd pfd;
- int retmask = , retval;
- memset(&pfd, , sizeof(pfd));
- pfd.fd = fd;
- if (mask & AE_READABLE) pfd.events |= POLLIN;
- if (mask & AE_WRITABLE) pfd.events |= POLLOUT;
- if ((retval = poll(&pfd, , milliseconds))== ) {
- if (pfd.revents & POLLIN) retmask |= AE_READABLE;
- if (pfd.revents & POLLOUT) retmask |= AE_WRITABLE;
- if (pfd.revents & POLLERR) retmask |= AE_WRITABLE;
- if (pfd.revents & POLLHUP) retmask |= AE_WRITABLE;
- return retmask;
- } else {
- return retval;
- }
- }
- //ae主函数
- void aeMain(aeEventLoop *eventLoop) {
- //stop初始为0
- eventLoop->stop = ;
- while (!eventLoop->stop) {
- //调用beforesleep函数
- if (eventLoop->beforesleep != NULL)
- eventLoop->beforesleep(eventLoop);
- //派发所有的事件
- aeProcessEvents(eventLoop, AE_ALL_EVENTS);
- }
- }
- //获取api名字
- char *aeGetApiName(void) {
- return aeApiName();
- }
- //sleep之前的回调函数
- void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep) {
- eventLoop->beforesleep = beforesleep;
- }
这就是ae文件里大体的几个api,其他的没理解的还在研究。
我的微信公众号:
对于redis框架的理解(三)的更多相关文章
- 对于redis框架的理解(四)
上一篇讲述了eventloop的结构和创建,添加文件事件删除文件事件,派发等等. 而eventloop主要就是调用不同网络模型完成事件监听和派发的. 这一篇主要讲述epoll网络模型,redis是如何 ...
- 对于redis框架的理解(二)
之前梳理过redis main函数主体流程 大体是 initServerConfig() -> loadServerConfig() -> daemonize() -> initSe ...
- redis 单线程的理解
单线程模型 Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程.其中执行命令阶段,由于Redis是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会 ...
- iOS10通知框架UserNotification理解与应用
iOS10通知框架UserNotification理解与应用 一.引言 关于通知,无论与远程Push还是本地通知,以往的iOS系统暴漏给开发者的接口都是十分有限的,开发者只能对标题和内容进行简单的定义 ...
- redis之(二十一)redis之深入理解Spring Redis的使用
关于spring redis框架的使用,网上的例子很多很多.但是在自己最近一段时间的使用中,发现这些教程都是入门教程,包括很多的使用方法,与spring redis丰富的api大相径庭,真是浪费了这么 ...
- Nginx Http框架的理解
Nginx Http框架的理解 HTTP框架是Nginx基础框架的一部分,Nginx的其它底层框架如master-worker进程模型.event模块.mail 模块等. HTTP框架代码主要有2个模 ...
- Redis 小白指南(三)- 事务、过期、消息通知、管道和优化内存空间
Redis 小白指南(三)- 事务.过期.消息通知.管道和优化内存空间 简介 <Redis 小白指南(一)- 简介.安装.GUI 和 C# 驱动介绍> 讲的是 Redis 的介绍,以及如何 ...
- Hadoop框架基础(三)
** Hadoop框架基础(三) 上一节我们使用eclipse运行展示了hdfs系统中的某个文件数据,这一节我们简析一下离线计算框架MapReduce,以及通过eclipse来编写关于MapReduc ...
- C#使用Thrift作为RPC框架入门(三)之三层架构
前言 这是我们讲解Thrift框架的第三篇文章,前两篇我们讲了Thrift作为RPC框架的基本用法以及架构的设计.为了我们更好的使用和理解Thrift框架,接下来,我们将来学习一下Thrift框架提供 ...
随机推荐
- 解决登录linux输入密码问题
1.使用密钥 ssh-keyssh -i .ssh/*.key root@<ip_addr> 2.使用sshpass 安装 rpm 包:yum install sshpass 配置文件: ...
- Selenium WebDriver 下 plugin container for firefox has stopped working
用selenium 的webdriver 和 firefox 浏览器做自动化测试,经常会出现 plugin container for firefox has stopped working 如下图所 ...
- git实验
四.实例应用 应用1.现有项目移植到git代管 进入目标项目,进行git初始化: 初始化:git init 修改config:git config -- local user.name '名称' 和 ...
- ORM(object relational Maping)
ORM即对象关系映射,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将java程序中的对象自动持久化到关系数据库中.本质上 ...
- unrecognized selector send to instancd 快速定位
1.在Debug菜单中Breakpoints->Create Symbolic Breakpoint; 2.在Symbolic中填写方法签名: -[NSObject(NSObject) does ...
- Rsyslog的三种传输协议简要介绍
rsyslog的三种传输协议 rsyslog 可以理解为多线程增强版的syslog. rsyslog提供了三种远程传输协议,分别是: 1. UDP 传输协议 基于传统UDP协议进行远程日志传输,也是传 ...
- 第5章 首次登录与在线求助man page
首次登录系统 centos默认图像界面为GNOME. Linux默认情况下会提供6个Terminal来让用户登录,切换方式为ctrl+alt+[F1-F6],系统将这六个操作界面命名为tty1-tty ...
- 【第八周】【新蜂】新NABCD
由小组成员宫成荣撰写 一.小组项目申请时提交的NABCD: 痛点:普通的俄罗斯方块是不现实距离下一级有多远的,我们的游戏能显示距离下一等级游戏有多远.方便玩家体验. nabc: n:能满足大多数玩家的 ...
- 【第三周】【】cppunit!
coding.net地址:https://coding.net/u/Boxer_ ssh:git@git.coding.net:Boxer_/homework.git https://coding.n ...
- Python入门:认识变量和字符串
几个月前,我开始学习个人形象管理,从发型.妆容.服饰到仪表仪态,都开始做全新改造,在塑造个人风格时,最基础的是先了解自己属于哪种风格,然后找到参考对象去模仿,可以是自己欣赏的人.明星或模特等,直至最后 ...