函数 aeCreateFileEvent 一开始 , 从 eventLoop->events 获取了一个 aeFileEvent 对象 。在 2.1 中我们介绍过 eventLoop->events 数组 , 注册的各种事件处理器会保存在这个地方 。
接下来调用 aeApiAddEvent 。这个函数其实就是对 epoll_ctl 的一个封装 。主要就是实际执行 epoll_ctl EPOLL_CTL_ADD 。
//file:src/ae_epoll.cstatic int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {// add or modint op = eventLoop->events[fd].mask == AE_NONE ?EPOLL_CTL_ADD : EPOLL_CTL_MOD;......// epoll_ctl 添加事件epoll_ctl(state->epfd,op,fd,&ee);return 0;}每一个 eventLoop->events 元素都指向一个 aeFileEvent 对象 。在这个对象上 , 设置了三个关键东西
- rfileProc:读事件回调
- wfileProc:写事件回调
- clientData:一些额外的扩展数据
回头看 initServer 调用 aeCreateFileEvent 时传参来看 。
//file: src/server.cvoid initServer() {......// 2.1.3 注册 accept 事件处理器for (j = 0; j < server.ipfd_count; j++) {aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,acceptTcpHandler,NULL);}}listen fd 对应的读回调函数 rfileProc 事实上就被设置成了 acceptTcpHandler , 写回调没有设置 , 私有数据 client_data 也为 null 。三、Redis 事件处理循环在上一节介绍完了 Redis 的启动初始化过程 , 创建了 epoll , 也进行了绑定监听 , 也注册了 accept 事件处理函数为 acceptTcpHandler 。
//file: src/server.cint main(int argc, char **argv) {......// 启动初始化initServer();// 运行事件处理循环 , 一直到服务器关闭为止aeMain(server.el);}接下来 , Redis 就会进入 aeMain 开始进行真正的用户请求处理了 。在 aeMain 函数中 , 是一个无休止的循环 。在每一次的循环中 , 要做如下几件事情 。
文章插图
- 通过 epoll_wait 发现 listen socket 以及其它连接上的可读、可写事件
- 若发现 listen socket 上有新连接到达 , 则接收新连接 , 并追加到 epoll 中进行管理
- 若发现其它 socket 上有命令请求到达 , 则读取和处理命令 , 把命令结果写到缓存中 , 加入写任务队列
- 每一次进入 epoll_wait 前都调用 beforesleep 来将写任务队列中的数据实际进行发送
- 如若有首次未发送完毕的 , 当写事件发生时继续发送
//file:src/ae.cvoid aeMain(aeEventLoop *eventLoop) {eventLoop->stop = 0;while (!eventLoop->stop) {// 如果有需要在事件处理前执行的函数 , 那么运行它// 3.4 beforesleep 处理写任务队列并实际发送之if (eventLoop->beforesleep != NULL)eventLoop->beforesleep(eventLoop);// 开始等待事件并处理// 3.1 epoll_wait 发现事件// 3.2 处理新连接请求// 3.3 处理客户连接上的可读事件aeProcessEvents(eventLoop, AE_ALL_EVENTS);}}以上就是 aeMain 函数的核心逻辑所在 , 接下来我们分别对如上提到的四件事情进行详细的阐述 。3.1 epoll_wait 发现事件Redis 不管有多少个用户连接 , 都是通过 epoll_wait 来统一发现和管理其上的可读(包括 liisten socket 上的 accept事件)、可写事件的 。甚至连 timer , 也都是交给 epoll_wait 来统一管理的 。

文章插图
每当 epoll_wait 发现特定的事件发生的时候 , 就会调用相应的事先注册好的事件处理函数进行处理 。我们来详细看 aeProcessEvents 对 epoll_wait 的封装 。
//file:src/ae.cint aeProcessEvents(aeEventLoop *eventLoop, int flags){// 获取最近的时间事件tvp = xxx// 处理文件事件 , 阻塞时间由 tvp 决定numevents = aeApiPoll(eventLoop, tvp);for (j = 0; j < numevents; j++) {// 从已就绪数组中获取事件aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];//如果是读事件 , 并且有读回调函数fe->rfileProc()//如果是写事件 , 并且有写回调函数fe->wfileProc()}}//file: src/ae_epoll.cstatic int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {// 等待事件aeApiState *state = eventLoop->apidata;epoll_wait(state->epfd,state->events,eventLoop->setsize,tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);...}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |3款网红“卸妆油”深度测评:MAC温和不刺激,植村秀虽贵但真好用
- 红茶喝上火吗,秋天上火喝红茶好吗
- 对联谜语答案及解析?对联猜谜大全及答案简单的
- 《亚瑟王的荣耀》铭文解析
- 冬天喝祁门红茶,祁门红茶女人喝好吗
- 茶香门第红茶,红茶的产地
- 迪奥香水广告解析
- 解析:书房风水为何不宜向阳
- 详细解析:书房风水挂什么字画好
- 姜文《让子弹飞》深度影评?姜文评价让子弹飞
