对于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框架提供 ...
随机推荐
- openstack-r版(rocky)搭建基于centos7.4 的openstack swift对象存储服务 三
openstack-r版(rocky)搭建基于centos7.4 的openstack swift对象存储服务 一 openstack-r版(rocky)搭建基于centos7.4 的openstac ...
- PytorchZerotoAll学习笔记(五)--逻辑回归
逻辑回归: 本章内容主要讲述简单的逻辑回归:这个可以归纳为二分类的问题. 逻辑,非假即真.两种可能,我们可以联想一下在继电器控制的电信号(0 or 1) 举个栗子:比如说你花了好几个星期复习的考试(通 ...
- presto 配置mysql.properties异常Database (catalog) must not be specified in JDBC URL for MySQL connector
在presto 0.210 以后配置mysql.properties的时候,对于jdbc-url属性配置后面要加上对应要链接的database connection-url=jdbc:mysql:// ...
- Java连接池
- firefox插件Firebug的使用教程
什么是Firebug 从事了数年的Web开发工作,越来越觉得现在对WEB开发有了更高的要求.要写出漂亮的HTML代码:要编写精致的CSS样式表展示每个页面模块:要调试 javascript给页面增加一 ...
- web登录密码加密
文章:如何实现登录页面密码加密 文章:用RSA加密实现Web登录密码加密传输 文章:web登录用户名密码加密 知乎文章:Web前端密码加密是否有意义? 文章:记录一次黑客模拟攻击 成功拿到淘宝账号和密 ...
- 从入门到不放弃——OO第一次作业总结
写在最前面: 我是一个这学期之前从未接触过java的小白,对面向对象的理解可能也只是停留在大一python讲过几节课的面向对象.幸运的是,可能由于前三次作业难度还是较低,并未给我造成太大的困难,接下来 ...
- Mac下Git的基础操作
目前最火的版本控制软件是Git了吧,今天简单梳理一下Mac下Git的基础操作~~ 一.什么是Git Git是一个分布式代码管理工具,用于敏捷的处理或大或小的项目,类似的工具还有svn. 基于Git的快 ...
- 高性能的HTTP代理 LittleProxy
引用: https://github.com/adamfisk/LittleProxy 拦截和操纵HTTPS流量,LittleProxy使用中间人(MITM)管理器. LittleProxy的默认实现 ...
- Ubuntu 16.04 LTS安装sogou输入法详解
http://blog.csdn.net/qq_21792169/article/details/53152700 最近开始学习linux 在安装输入法中遇到的一些问题,最终成功安装,也得益于网络上的 ...