两种:
- file event 监听并处理事件
- time event 定时执行事件
阅读源码:
- initServer 里先 aeCreateEventLoop 把 event 链表创建出来,开辟内存
- listenToPort 根据用户配置创建 socket 并 bind 到指定端口,listen 等待客户端连接
- aeCreateFileEvent 注册文件事件
- 其实就是把 acceptTcpHandler 回调绑定给 eventLoop 中的
aeFileEvent *fe = &eventLoop->events[fd];
- 在接收到
AE_READABLE
事件时,会调用fe->rfileProc
回调函数 - 因此,想要将
acceptTcpHandler
绑定到AE_READABLE
事件,if (mask & AE_READABLE) fe->rfileProc = proc;
即可
- 其实就是把 acceptTcpHandler 回调绑定给 eventLoop 中的
基于 Reactor 模式的 file event handler
- I/O 多路复用
- 监听套接字
套接字 -> I/O 多路复用 -> 文件事件分派器 dispatcher -> 文件事件处理器
有多种实现方式: select
, epoll
, kqueue
, epoll
等。
实现同一套函数签名,在编译器根据宏定义选择不同实现。
src/ae.h
#define AE_NONE 0
#define AE_READABLE 1
#define AE_WRITABLE 2
- 客户端对套接字 write 、或执行 close ,或客户端对服务器的监听套接字执行 connect (有新的 acceptable 套接字出现),产生 AE_READABLE 事件
- 客户端对套接字执行 read ,产生 AE_WRITABLE 事件
参考 src/ae.c
注册 Event 是动态的,感兴趣可以看 prepareClientToWrite
。
其实也把 aeCreateTimeEvent 注册到 eventLoop 的 events 数组里,不过是注册到 timeEventHead 链表里。
aeProcessEvents
中 aeSearchNearestTimer
找到最近的定时事件;之后 aeApiPoll
负责文件事件。
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}