很高兴,我们历尽艰难险阻,来到了函数aeMain(server.el)
这个函数是主循环函数,源码如下:
void aeMain(aeEventLoop *eventLoop){
eventLoop->stop = 0;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}
~~~~~~~~~~~~~~
eventLoop->stop = 0;//设置stop标志为0
eventLoop->beforesleep(eventLoop);还不到分析的时候,暂且不分析。
毕竟现在还没有数据,现在分析也没法分析,后面就可以了。
aeProcessEvents(eventLoop, AE_ALL_EVENTS);//处理各种事件
让我们去关注如何执行的。
~~~~~~~~~~~~~~~~~
/* Nothing to do? return ASAP */if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0;
//如果任何一种事件都不处理,则返回
其实这个函数是处理2种行为的,来看具体的原理。
有些地方暂时不说,
主要先关注aeApiPoll(eventLoop, tvp);
显然是从之前的监听端口中accept出一个连接来处理。
这个函数内部通过retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
来获取可accept的对象。
重点关注下面两行:
eventLoop->fired[j].fd = e->data.fd;eventLoop->fired[j].mask = mask;
也就是先把可以处理的socket存储在fired数组里。
~~~~~~~~~~~~~~~
接着执行下面这个代码:
for (j = 0; 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 = 0;
/* note the fe->mask & mask & ... code: maybe an already processed
* event removed an element that fired and we still didn't
* processed, so we check if the event is still valid. */
if (fe->mask & mask & AE_READABLE) {
rfired = 1;
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++;
}
我们来看具体的执行过程。
aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
这个代码的作用是取出events对象,如果读者这个时候去观察events数组,就知道之前这个数组的样子是这样的:
aeFileEvent *events; /* Registered events */
//( server.maxclients+REDIS_EVENTLOOP_FDSET_INCR ) * sizeof(aeFileEvent)
//下标与句柄ID相同
//且每个event.mask = AE_NONE|AE_READABLE 、、
// .rfileProc = acceptTcpHandler
//.clientData= NULL
也就是说,存储了mask和读处理函数。
~~~~~~
int mask = eventLoop->fired[j].mask;
mask标志了当前socket可以做的事情。
int fd = eventLoop->fired[j].fd;、、标志了当前socket的句柄号。
~~~~
if (fe->mask & mask & AE_READABLE)
{
//如果可以读
rfired = 1;//记忆是否曾经有可读的socket
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
//触发读函数。
}
对于监听server socket来说,读函数为:acceptTcpHandler
显然里面会调用accept来获取客户连接服务器的连接并加入到server->el.apidata.fd中去监听。
洗澡,然后睡觉!